GraphQL API Reference

Introduction

The Feedframer GraphQL API provides a flexible, powerful alternative to the REST API. With GraphQL, you request exactly the data you need—nothing more, nothing less—in a single request.

The GraphQL API uses the same account selection logic as the REST /api/v1/me endpoint, returning account information along with posts for that account.

Endpoint

https://feedframer.com/graphql

Authentication

Include your API key as a query parameter:

GET https://feedframer.com/graphql?api_key=YOUR_API_KEY&query=...

All GraphQL requests use GET for optimal caching by Cloudflare CDN.

See Authentication for details.

GraphQL Explorer

The best way to explore the GraphQL API is using the GraphQL Explorer in your dashboard. It features:

  • Interactive query editor with syntax highlighting
  • Auto-completion and schema documentation
  • Example queries to get started
  • Code generation for multiple languages
  • Real-time response preview

Schema Overview

Query Types

me

Get Instagram account and posts for the authenticated user. Behaves like the REST /api/v1/me endpoint.

Account Selection:

  • If account parameter is provided: returns posts from that specific account
  • If no account parameter: returns posts from the most recent connected account

Arguments:

Argument Type Description
first Int Number of posts to return (default: 12, max: 100)
page Int Page number for cursor pagination
type String Filter by post type: IMAGE, VIDEO, CAROUSEL_ALBUM, REELS
account String Filter by Instagram username (defaults to most recent account)
publishedAfter DateTimeTz Filter posts published after this date
publishedBefore DateTimeTz Filter posts published before this date
orderBy [OrderByClause!] Sort results (default: published_at DESC)
format String Premium only. Image format for responsive images: jpg or webp (default: jpg)

Returns: AccountWithPostsResponse containing account info, posts array, and pagination metadata

Object Types

AccountWithPostsResponse

The main response type containing account information and posts (similar to REST /api/v1/me endpoint).

Field Type Description
username String! Instagram username
name String Display name
biography String Account biography
website String Website URL
profilePictureUrl String Profile picture URL (locally stored with fallback)
followersCount Int Number of followers
followsCount Int Number of accounts followed
mediaCount Int Total media count
posts [Post!]! Array of posts
pagination PaginationInfo! Pagination metadata

Post

Field Type Description
id ID! Feedframer internal post ID
instagramPostId String! Instagram's unique post ID
type String! Post type (IMAGE, VIDEO, CAROUSEL_ALBUM, REELS)
caption String Post caption text
altText String Alt text for the post (currently not provided by Instagram API)
mediaUrl String! URL to media file (locally stored with fallback)
thumbnailUrl String Video thumbnail URL (locally stored with fallback)
sizes JSON Premium only. Responsive image URLs at different sizes (320px, 768px, 960px, 1200px). Uses thumbnail for videos.
permalink String! Instagram post URL
commentsCount Int Number of comments
likeCount Int Number of likes
children JSON Carousel children posts (for CAROUSEL_ALBUM type)
comments JSON Comments data from Instagram API
publishedAt DateTimeTz! When posted to Instagram
lastUpdatedAt DateTimeTz! When this post was last updated on Instagram
fetchedAt DateTimeTz! When post was last fetched from Instagram
createdAt DateTimeTz! When post was created in Feedframer
updatedAt DateTimeTz! When post was last updated in Feedframer
instagramAccount InstagramAccount Related Instagram account

InstagramAccount

Field Type Description
id ID! Account ID
instagramUserId String! Instagram user ID from API
username String! Instagram username
name String Display name
biography String Account biography
website String Website URL
profilePictureUrl String Profile picture URL (locally stored with fallback)
followersCount Int Number of followers
followsCount Int Number of accounts followed
mediaCount Int Total media count
status String! Account status (active, expired, disconnected, token_invalid)
lastFetchAt DateTimeTz When posts were last fetched
createdAt DateTimeTz! When account was created
updatedAt DateTimeTz! When account was last updated
posts [Post!]! Posts from this account

PaginationInfo

Cursor-based pagination metadata (matches REST API format).

Field Type Description
nextCursor String Cursor for the next page (null if no more pages)
prevCursor String Cursor for the previous page (null if on first page)
hasMore Boolean! Whether there are more pages
perPage Int! Items per page

Example Queries

Basic Query

Get account info with latest 12 posts:

query GetMe {
  me(first: 12) {
    username
    name
    profilePictureUrl
    posts {
      id
      instagramPostId
      caption
      mediaUrl
      publishedAt
    }
    pagination {
      nextCursor
      hasMore
      perPage
    }
  }
}

Full Account and Post Data

Request all available fields:

query GetMe {
  me(first: 12, format: "jpg") {
    username
    name
    biography
    website
    profilePictureUrl
    followersCount
    followsCount
    mediaCount
    posts {
      id
      instagramPostId
      type
      caption
      altText
      mediaUrl
      thumbnailUrl
      sizes  # Premium only
      permalink
      commentsCount
      likeCount
      children
      comments
      publishedAt
      lastUpdatedAt
      fetchedAt
    }
    pagination {
      nextCursor
      prevCursor
      hasMore
      perPage
    }
  }
}

Filter by Type

Get only video posts:

query GetMe {
  me(first: 12, type: "VIDEO") {
    username
    posts {
      id
      caption
      mediaUrl
      thumbnailUrl
      publishedAt
    }
  }
}

Filter by Specific Account

Get posts from a specific Instagram account:

query GetMe {
  me(first: 12, account: "your_username") {
    username
    followersCount
    posts {
      id
      caption
      mediaUrl
      publishedAt
    }
  }
}

Filter by Date Range

Get posts from a specific time period:

query GetMe {
  me(
    first: 12
    publishedAfter: "2024-01-01T00:00:00Z"
    publishedBefore: "2024-01-31T23:59:59Z"
  ) {
    username
    posts {
      id
      caption
      publishedAt
    }
  }
}

Custom Sorting

Sort results by publish date (ascending):

query GetMe {
  me(
    first: 12
    orderBy: [{ column: "published_at", order: ASC }]
  ) {
    username
    posts {
      id
      caption
      publishedAt
    }
  }
}

Pagination with Cursor

Navigate through pages using cursor:

query GetMe {
  me(first: 12, page: 2) {
    username
    posts {
      id
      caption
      publishedAt
    }
    pagination {
      nextCursor
      prevCursor
      hasMore
      perPage
    }
  }
}

Complex Query

Combine multiple features:

query GetMe {
  me(
    first: 24
    type: "VIDEO"
    orderBy: [{ column: "published_at", order: DESC }]
  ) {
    username
    name
    profilePictureUrl
    followersCount
    posts {
      id
      caption
      mediaUrl
      thumbnailUrl
      likeCount
      commentsCount
      publishedAt
    }
    pagination {
      nextCursor
      hasMore
    }
  }
}

Responsive Images (Premium)

Get optimized responsive image URLs:

query GetPostsWithResponsiveImages {
  me(first: 12, format: "webp") {
    username
    posts {
      id
      caption
      altText
      mediaUrl
      thumbnailUrl
      sizes  # Premium only: contains 320, 768, 960, 1200 width URLs
      publishedAt
    }
  }
}

Example Response:

{
  "data": {
    "me": {
      "username": "your_username",
      "posts": [
        {
          "id": "1",
          "caption": "Beautiful sunset!",
          "altText": null,
          "mediaUrl": "https://cdn.feedframer.com/your_username/123_media.jpg",
          "thumbnailUrl": null,
          "sizes": {
            "320": "https://cdn.feedframer.com/cdn-cgi/image/width=320,format=webp/your_username/123_media.jpg",
            "768": "https://cdn.feedframer.com/cdn-cgi/image/width=768,format=webp/your_username/123_media.jpg",
            "960": "https://cdn.feedframer.com/cdn-cgi/image/width=960,format=webp/your_username/123_media.jpg",
            "1200": "https://cdn.feedframer.com/cdn-cgi/image/width=1200,format=webp/your_username/123_media.jpg"
          },
          "publishedAt": "2024-01-15T18:30:00+00:00"
        }
      ]
    }
  }
}

Note: The sizes field is only available for premium users. Free tier users will receive null. For video posts, the responsive URLs use the thumbnail image.

Making Requests

All GraphQL requests use GET for optimal CDN caching. The query is passed as a URL-encoded parameter.

cURL

curl -G 'https://feedframer.com/graphql' \
  --data-urlencode 'api_key=YOUR_API_KEY' \
  --data-urlencode 'query=query { me(first: 12) { username posts { id caption mediaUrl publishedAt } } }'

JavaScript (Fetch API)

const query = `
  query GetMe {
    me(first: 12) {
      username
      name
      profilePictureUrl
      posts {
        id
        caption
        mediaUrl
        publishedAt
      }
      pagination {
        nextCursor
        hasMore
      }
    }
  }
`;

const url = 'https://feedframer.com/graphql?' + new URLSearchParams({
  api_key: 'YOUR_API_KEY',
  query: query
});

fetch(url, {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
  }
})
  .then(res => res.json())
  .then(data => console.log(data.data.me))
  .catch(error => console.error('Error:', error));

PHP

<?php

$query = <<<'GRAPHQL'
query GetMe {
  me(first: 12) {
    username
    name
    profilePictureUrl
    posts {
      id
      caption
      mediaUrl
      publishedAt
    }
    pagination {
      nextCursor
      hasMore
    }
  }
}
GRAPHQL;

$url = 'https://feedframer.com/graphql?' . http_build_query([
    'api_key' => 'YOUR_API_KEY',
    'query' => $query
]);

$data = json_decode(file_get_contents($url), true);
print_r($data['data']['me']);

Python

import requests

query = """
query GetMe {
  me(first: 12) {
    username
    name
    profilePictureUrl
    posts {
      id
      caption
      mediaUrl
      publishedAt
    }
    pagination {
      nextCursor
      hasMore
    }
  }
}
"""

response = requests.get(
    'https://feedframer.com/graphql',
    params={
        'api_key': 'YOUR_API_KEY',
        'query': query
    }
)

data = response.json()
print(data['data']['me'])

Response Format

Successful responses contain a data object:

{
  "data": {
    "posts": {
      "username": "your_username",
      "name": "Your Name",
      "biography": "Your bio",
      "website": "https://example.com",
      "profilePictureUrl": "https://...",
      "followersCount": 1234,
      "followsCount": 567,
      "mediaCount": 89,
      "posts": [
        {
          "id": "1",
          "instagramPostId": "123456789",
          "caption": "Beautiful sunset!",
          "mediaUrl": "https://...",
          "publishedAt": "2024-01-15T18:30:00+00:00"
        }
      ],
      "pagination": {
        "nextCursor": "eyJpZCI6MTJ9",
        "prevCursor": null,
        "hasMore": true,
        "perPage": 12
      }
    }
  }
}

Error Responses

Errors are returned in the errors array:

{
  "errors": [
    {
      "message": "The specified Instagram account does not exist or does not belong to you.",
      "extensions": {
        "category": "validation"
      },
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}

Common error messages:

  • Unauthenticated - Missing or invalid API key
  • You have not connected any Instagram accounts yet. - No connected accounts
  • The specified Instagram account does not exist or does not belong to you. - Invalid account filter

Variables

Use variables for dynamic queries:

Query:

query GetPosts($first: Int!, $type: String, $account: String) {
  me(first: $first, type: $type, account: $account) {
    username
    posts {
      id
      caption
      mediaUrl
    }
  }
}

Variables:

{
  "first": 24,
  "type": "IMAGE",
  "account": "your_username"
}

Request:

const url = 'https://feedframer.com/graphql?' + new URLSearchParams({
  api_key: 'YOUR_API_KEY',
  query: queryString,
  variables: JSON.stringify({
    first: 24,
    type: 'IMAGE',
    account: 'your_username'
  })
});

fetch(url, {
  method: 'GET',
  headers: { 'Accept': 'application/json' }
});

Caching

All GraphQL requests use GET for optimal caching by Cloudflare CDN:

  • Responses are cached for 1 hour
  • Identical queries return cached results instantly
  • Cache headers are preserved (cache-control: max-age=3600, public)

This makes GraphQL queries extremely fast for repeated requests.

Tier Limits

Free Tier:

  • Maximum 12 posts per page
  • Single account access

Premium Tier:

  • Up to 100 posts per page
  • Unlimited accounts

Best Practices

Request Only What You Need

One of GraphQL's strengths is requesting only the fields you need:

# ✅ Good - request only what you need
query {
  me(first: 12) {
    username
    posts {
      mediaUrl
      caption
    }
  }
}

# ❌ Wasteful - requesting unnecessary fields
query {
  me(first: 12) {
    username
    name
    biography
    website
    profilePictureUrl
    followersCount
    followsCount
    mediaCount
    posts {
      id
      instagramPostId
      type
      caption
      mediaUrl
      thumbnailUrl
      permalink
      commentsCount
      likeCount
      publishedAt
      lastUpdatedAt
      createdAt
      updatedAt
    }
  }
}

Use Fragments for Reusability

Define reusable fragments:

fragment PostFields on Post {
  id
  caption
  altText
  mediaUrl
  thumbnailUrl
  sizes  # Premium only
  publishedAt
}

fragment AccountInfo on AccountWithPostsResponse {
  username
  name
  profilePictureUrl
}

query {
  me(first: 12, format: "jpg") {
    ...AccountInfo
    posts {
      ...PostFields
    }
  }
}

Named Queries

Always name your queries for better debugging:

# ✅ Good
query GetLatestPosts {
  me(first: 12) { ... }
}

# ❌ Avoid
query {
  me(first: 12) { ... }
}

Comparison with REST API

The GraphQL me query is equivalent to the REST GET /api/v1/me endpoint:

GraphQL:

query {
  me(first: 12, account: "username") {
    username
    posts { id caption mediaUrl }
  }
}

REST:

GET /api/v1/me?page[size]=12&filter[account]=username

Advantages of GraphQL:

  • Request only the fields you need
  • Single request for account + posts
  • Strong typing and schema introspection
  • Better developer experience with tooling
  • GET requests enable CDN caching (same as REST)

Advantages of REST:

  • Simpler for basic use cases
  • Standard HTTP semantics
  • More familiar to developers

Framework Integration

For complete integration examples with GraphQL, see:

Next Steps