Filtering & Sorting
Introduction
You can narrow the posts you get back by type and by publish date, and choose their order. This page covers every filter and sort option for the REST endpoint GET /api/v1/me and the GraphQL me query.
The examples use curl. Pass -g so curl doesn't treat the square brackets as a pattern.
Free and Premium
Filters and sorting work the same way on both plans, but they apply to different sets of posts:
- Premium keys filter and sort every post Feedframer has stored for the account, and can page through the results. See Pagination.
- Free keys only ever see the account's 6 most recent posts. Filters and sorting apply within those 6.
filter[type]=VIDEOreturns the videos among the latest 6, which may be none.sort=published_atreturns the same 6 posts, oldest first. A date range that ends before the sixth-newest post returns nothing.
Filter by post type
| Value | Returns |
|---|---|
IMAGE |
Single-image posts |
VIDEO |
Video posts, including reels |
CAROUSEL_ALBUM |
Posts with several images or videos |
REELS |
The same posts as VIDEO |
Instagram reports reels as VIDEO and doesn't give Feedframer a separate type for them, so REELS is accepted as another name for VIDEO. The posts come back with mediaType: "VIDEO". Since Instagram turned video posts into reels in 2022, almost every VIDEO post is a reel.
REST: filter[type]. Case doesn't matter, so image works too.
# Images only
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=IMAGE'
# Videos and reels (these two return the same posts)
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=VIDEO'
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=REELS'
# Carousels only
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=CAROUSEL_ALBUM'
GraphQL: the type argument. Use upper case: GraphQL rejects "video".
query {
me(type: "VIDEO") {
posts {
id
type
thumbnailUrl
permalink
}
}
}
In GraphQL the post's type is the type field. In REST it is mediaType.
For video posts, show thumbnailUrl in an <img>. mediaUrl is usually an .mp4 file.
Filter by date
| REST parameter | GraphQL argument | Keeps posts published |
|---|---|---|
filter[publishedAfter] |
publishedAfter |
at or after this time |
filter[publishedBefore] |
publishedBefore |
at or before this time |
Rules:
- Both bounds are inclusive. A post published at exactly the time you give is included.
- Use ISO 8601. A date (
2026-03-25) or a date and time (2026-03-25T15:10:06Z,2026-03-25T16:10:06+01:00). - Offsets are honoured.
2026-03-25T16:10:06+01:00means 15:10:06 UTC. A time with no offset is read as UTC. - A plain date on
publishedAftermeans 00:00:00 UTC on that day. - A plain date on
publishedBeforecovers the whole day, up to 23:59:59 UTC. SopublishedBefore=2026-03-31includes posts from 31 March. - Encode
+as%2Bin REST query strings. An unencoded+turns into a space, and the request fails with a422.Zneeds no encoding. In GraphQL you send dates inside the JSON body, so no encoding is needed.
Post times in responses are UTC (timestamp in REST, publishedAt in GraphQL).
REST:
# Posts published in March 2026 (1 March 00:00 UTC to 31 March 23:59:59 UTC)
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[publishedAfter]=2026-03-01&filter[publishedBefore]=2026-03-31'
# Posts published on or after 1 January 2026
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[publishedAfter]=2026-01-01'
# Posts published before 9am UK summer time on 25 March 2026 (note the %2B)
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[publishedBefore]=2026-03-25T09:00:00%2B01:00'
GraphQL:
query {
me(publishedAfter: "2026-03-01", publishedBefore: "2026-03-31") {
posts {
id
caption
publishedAt
}
}
}
If publishedAfter is later than publishedBefore, you get an empty posts array, not an error.
Combining filters
Filters combine with AND: a post must match all of them.
REST:
# Image posts from March 2026
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=IMAGE&filter[publishedAfter]=2026-03-01&filter[publishedBefore]=2026-03-31'
GraphQL:
query {
me(type: "IMAGE", publishedAfter: "2026-03-01", publishedBefore: "2026-03-31") {
posts {
id
mediaUrl
publishedAt
}
}
}
There is no filter by account. Each API key belongs to one Instagram account, so the key already decides which account's posts you get.
Sorting
The default order is newest first.
REST: the sort parameter
| Value | Order |
|---|---|
-published_at |
Newest first. This is the default. |
published_at |
Oldest first |
-publishedAt |
Same as -published_at |
publishedAt |
Same as published_at |
-id |
Most recently stored by Feedframer first |
id |
First stored by Feedframer first |
A leading - means descending. id is the order Feedframer stored the posts, not Instagram's post id. It usually matches publish order, but not always. There is no sorting by likes or comments.
# Oldest first
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&sort=published_at'
# Most recently stored first
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&sort=-id'
Any other value returns a 422 (see Errors below).
GraphQL: the orderBy argument
orderBy takes a list of { column, order } clauses:
column:published_at(orpublishedAt), oridorder:ASCorDESC
Only the first clause is used.
# Oldest first
query {
me(orderBy: [{ column: "published_at", order: ASC }]) {
posts {
id
publishedAt
}
}
}
# Most recently stored first
query {
me(orderBy: [{ column: "id", order: DESC }]) {
posts {
id
publishedAt
}
}
}
Practical examples
The latest 3 posts
page[size] sets how many posts come back. This works on both plans.
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&page[size]=3'
query {
me(first: 3) {
posts {
id
caption
publishedAt
}
}
}
A video grid
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=VIDEO'
const apiKey = 'YOUR_API_KEY';
const url = new URL('https://feedframer.com/api/v1/me');
url.searchParams.set('api_key', apiKey);
url.searchParams.set('filter[type]', 'VIDEO');
const response = await fetch(url);
const body = await response.json();
if (!response.ok) {
throw new Error(`${body.errors[0].code}: ${body.errors[0].detail}`);
}
const html = body.posts
.map((post) => `<a href="${post.permalink}"><img src="${post.thumbnailUrl}" alt="" loading="lazy"></a>`)
.join('');
On Free this returns only the videos among the 6 most recent posts, so the grid may be short or empty.
Images from a date range, oldest first
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=IMAGE&filter[publishedAfter]=2026-01-01&filter[publishedBefore]=2026-03-31&sort=published_at'
query {
me(
type: "IMAGE"
publishedAfter: "2026-01-01"
publishedBefore: "2026-03-31"
orderBy: [{ column: "published_at", order: ASC }]
) {
posts {
id
mediaUrl
publishedAt
}
pagination {
nextCursor
hasMore
}
}
}
On Premium, if hasMore is true, fetch the rest with the cursor, keeping the same filters and sort. See Pagination.
Filtering with variables in GraphQL
Pass filters as variables rather than building the query string yourself:
const apiKey = 'YOUR_API_KEY';
const query = `
query Posts($type: String, $after: DateTimeTz) {
me(type: $type, publishedAfter: $after) {
posts { id type publishedAt permalink }
}
}
`;
const response = await fetch(`https://feedframer.com/graphql?api_key=${apiKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables: { type: 'IMAGE', after: '2026-01-01' } }),
});
const body = await response.json();
if (!response.ok) {
// 401: bad or missing API key, in the REST error format
throw new Error(body.errors[0].code);
}
if (body.errors) {
// GraphQL errors, e.g. an invalid type or date
throw new Error(body.errors[0].message);
}
console.log(body.data.me.posts);
Errors
REST
An invalid filter or sort value returns HTTP 422 with one entry per bad parameter:
curl -g 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=STORY&filter[publishedAfter]=not-a-date&sort=likes'
{
"errors": [
{
"status": "422",
"code": "VALIDATION_ERROR",
"title": "Invalid Parameter",
"detail": "The selected filter[type] is invalid.",
"source": { "parameter": "filter[type]" }
},
{
"status": "422",
"code": "VALIDATION_ERROR",
"title": "Invalid Parameter",
"detail": "The filter[publishedAfter] field must be a valid date.",
"source": { "parameter": "filter[publishedAfter]" }
},
{
"status": "422",
"code": "VALIDATION_ERROR",
"title": "Invalid Parameter",
"detail": "The sort value must be one of: -published_at, published_at, -publishedAt, publishedAt, -id, id.",
"source": { "parameter": "sort" }
}
]
}
GraphQL
GraphQL returns HTTP 200 with an errors array. For a bad type or orderBy, data.me is null. For a bad date, the response has no data at all.
- An invalid
typegives the messageValidation failed for the field [me].with the detail inextensions.validation.type:["The selected type is invalid."]. - An invalid date gives a message like
"not-a-date" is not a valid date. Use ISO 8601, e.g. 2024-01-31 or 2024-01-31T09:00:00Z. - An unknown
orderBycolumn givesCannot order by "likes". Use published_at or id.
See Error Handling.
Next steps
- Pagination: page through filtered results
- REST API: the full REST reference
- GraphQL API: the full GraphQL reference