# Instagram API media fields: what /me/media returns and when

**Status, checked 2026-09-18:** the field rules below follow the IG Media reference as Meta published it on 2026-09-18. `caption` and `media_product_type` are marked there for Facebook Login only, so confirm both with your own Instagram Login token.

> Each field you can name in `fields=` on the media edge of the Instagram API with Instagram Login: when it comes back, what it holds, and how to turn it into a portable post object.

Canonical: https://electricblaze.com/developer/instagram-feed/media-fields.html

## At a glance

- **Use it when:** you are writing the `fields=` list for `/me/media` or `/<IG_ID>/media` on `graph.instagram.com` and need to know which field holds the picture, the video cover, the post link or the carousel items.
- **Do not use it when:** the owner will not create a Meta app or keep a token alive. A hosted feed returns posts without any `fields=` list; see the [feed API comparison](https://electricblaze.com/developer/instagram-feed/comparison.html).
- **What the human does:** nothing for the field list itself. The account must already be a Business or Creator account that granted `instagram_business_basic` to your app ([access tokens](https://electricblaze.com/developer/instagram-feed/access-token.html)).
- **Next step:** run the request below with your token, check whether `caption` and `media_product_type` come back, then convert each item with `toPost()`.

## Name every field you render

Without `fields=`, the media edge answers with bare ids. The edge is `GET https://graph.instagram.com/v25.0/<IG_ID>/media`, and an item carries nothing but its `id` until you list more ([Meta: get started with Instagram Login](https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/get-started), checked 2026-09-18).

Most examples call `/me/media`, where `me` is the account the token was issued for; for your own account both paths list the same posts.

Why v25.0: Meta's Instagram examples use v25.0 (released 2026-02-18, available until 2028-07-29); the newest Graph API version is v26.0 (2026-07-29) ([Meta: Graph API changelog](https://developers.facebook.com/docs/graph-api/changelog), checked 2026-09-18). This page matches those examples. Moving to v26.0 is a one-line change once you have compared both responses for your account.

Terminal (token read from your server environment):

```sh
curl -sG "https://graph.instagram.com/v25.0/me/media" \
  --data-urlencode "fields=id,caption,media_type,media_product_type,media_url,thumbnail_url,permalink,timestamp,username,like_count,comments_count,children{media_type,media_url,thumbnail_url}" \
  --data-urlencode "limit=3" \
  --data-urlencode "access_token=$IG_ACCESS_TOKEN"
```

Two names in that list, `caption` and `media_product_type`, may be refused or silently left out for an Instagram Login token. If the call errors, remove them one at a time and log which ones return.

## Field reference

Thirteen fields cover a typical feed. Apart from `id`, a field is returned only when you name it.

| Field | Returned | Notes |
|---|---|---|
| `id` | Always | Media id. Use it as the key when you merge pages or cache posts. |
| `caption` | Documented for Facebook Login only; test it | Post text. Treat it as optional and default to an empty string. |
| `media_type` | When named | `IMAGE`, `VIDEO` or `CAROUSEL_ALBUM`. A reel is reported as `VIDEO`. |
| `media_product_type` | Documented for Facebook Login only; test it | `AD`, `FEED`, `STORY` or `REELS`. The one documented reel flag. |
| `media_url` | When named, except for copyright-flagged media | Signed link to the photo, or to the video file for `VIDEO`. It expires; see [media URL expired](https://electricblaze.com/developer/instagram-feed/media-url-expired.html). |
| `thumbnail_url` | `VIDEO` only | Cover frame of a video. Use it as the grid tile for videos and reels. |
| `permalink` | Top-level posts; does not work on carousel children | The post on instagram.com. Link carousel items to the parent post. |
| `timestamp` | When named | Publication time with a `+0000` offset, for example `2026-09-12T07:41:00+0000`. |
| `username` | When named | Handle of the account that owns the post. |
| `children` | `CAROUSEL_ALBUM` only | Ids only, unless expanded as `children{media_type,media_url,thumbnail_url}`. |
| `like_count` | When named; not verified by us with Instagram Login | Number of likes. Keep the UI working when it is missing. |
| `comments_count` | When named; not verified by us with Instagram Login | Number of comments. Same caution as `like_count`. |
| `is_shared_to_feed` | Reels only | A reel-only flag about feed placement. Its value on other media is undefined, so it is no reel detector. |

Sources: [Meta: IG Media reference](https://developers.facebook.com/docs/instagram-platform/reference/instagram-media), checked 2026-09-18; [Meta: IG Media children](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-media/children), checked 2026-09-18.

The `+0000` offset has no colon, which is outside the ECMAScript date format, so rewrite it as `+00:00` before calling `new Date()`.

No default or maximum `limit` for this edge appears in the Meta pages we read on 2026-09-18. Pass the number of posts you actually draw and follow `paging.next` when you need more.

## Reels, videos and carousels

### Telling a reel from another video

Reels and ordinary videos share `media_type: "VIDEO"`. Only `media_product_type` separates them, and the IG Media reference labels it this way:

> Available for Instagram API with Facebook Login only
>
> [Meta: IG Media reference](https://developers.facebook.com/docs/instagram-platform/reference/instagram-media), checked 2026-09-18

With Instagram Login a reel badge is therefore not guaranteed. If your token returns `media_product_type`, filter on `REELS`. If it does not, draw every `VIDEO` the same way and leave the reel label off. A guess from the shape of `permalink` relies on undocumented URL patterns.

### Carousel items

On a `CAROUSEL_ALBUM`, the `children` edge lists the slides as bare ids. Expanding it inline as `children{media_type,media_url,thumbnail_url}` returns each slide in the same response ([Meta: IG Media children](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-media/children), checked 2026-09-18), which saves one extra request per slide.

Slides have no working `permalink` ([Meta: IG Media reference](https://developers.facebook.com/docs/instagram-platform/reference/instagram-media), checked 2026-09-18), so every slide should open the parent post. A video slide has its own `thumbnail_url`, like a top-level video.

### When media_url is missing

Instagram leaves `media_url` out when a post contains copyrighted material or was flagged for a copyright violation ([Meta: IG Media reference](https://developers.facebook.com/docs/instagram-platform/reference/instagram-media), checked 2026-09-18). Skip that post, or show a text card that links to `permalink`. Never render an empty `<img>`.

## Example response

A photo, a reel and a two-slide carousel, followed by the cursor block that pages the list.

Example response, trimmed (ids, URLs, cursors and the token are placeholders; `caption` and `media_product_type` appear only if your token returns them):

```json
{
  "data": [
    {
      "id": "17900000000000001",
      "caption": "Example caption for a photo post.",
      "media_type": "IMAGE",
      "media_product_type": "FEED",
      "media_url": "https://scontent.cdninstagram.com/v/example/photo-1.jpg?stp=example&oe=6AB0F580",
      "permalink": "https://www.instagram.com/p/EXAMPLE1/",
      "timestamp": "2026-09-12T07:41:00+0000",
      "username": "example.account",
      "like_count": 412,
      "comments_count": 23
    },
    {
      "id": "17900000000000002",
      "caption": "Example caption for a reel.",
      "media_type": "VIDEO",
      "media_product_type": "REELS",
      "media_url": "https://scontent.cdninstagram.com/v/example/reel-1.mp4?stp=example&oe=6AB0F580",
      "thumbnail_url": "https://scontent.cdninstagram.com/v/example/reel-1-cover.jpg?stp=example&oe=6AB0F580",
      "permalink": "https://www.instagram.com/reel/EXAMPLE2/",
      "timestamp": "2026-09-10T16:05:00+0000",
      "username": "example.account",
      "like_count": 1287,
      "comments_count": 64
    },
    {
      "id": "17900000000000003",
      "media_type": "CAROUSEL_ALBUM",
      "media_product_type": "FEED",
      "permalink": "https://www.instagram.com/p/EXAMPLE3/",
      "timestamp": "2026-09-08T11:20:00+0000",
      "username": "example.account",
      "children": {
        "data": [
          {
            "media_type": "IMAGE",
            "media_url": "https://scontent.cdninstagram.com/v/example/slide-1.jpg?stp=example&oe=6AB0F580",
            "id": "17900000000000031"
          },
          {
            "media_type": "VIDEO",
            "media_url": "https://scontent.cdninstagram.com/v/example/slide-2.mp4?stp=example&oe=6AB0F580",
            "thumbnail_url": "https://scontent.cdninstagram.com/v/example/slide-2-cover.jpg?stp=example&oe=6AB0F580",
            "id": "17900000000000032"
          }
        ]
      }
    }
  ],
  "paging": {
    "cursors": {
      "before": "EXAMPLE_BEFORE_CURSOR",
      "after": "EXAMPLE_AFTER_CURSOR"
    },
    "next": "https://graph.instagram.com/v25.0/17841400000000000/media?access_token=EXAMPLE_TOKEN&fields=id%2Cmedia_type&limit=3&after=EXAMPLE_AFTER_CURSOR"
  }
}
```

Pagination is cursor-based: `paging.cursors` holds `before` and `after`, and `paging.next` is the URL of the following page. A page may hold fewer items than `limit`, so stop when `paging.next` is absent, not when a page comes back short ([Meta: Graph API paginated results](https://developers.facebook.com/docs/graph-api/results), checked 2026-09-18).

When `paging.next` includes `access_token`, it is a secret. Follow it on the server and never hand it to browser code.

## Map the fields to ElectricBlaze schema v1

[Schema v1](https://electricblaze.com/developer/instagram-feed/schema.html) is a platform-neutral post shape: `type` tells a component what to draw, and `format` carries the platform's own name for the post. Converting Graph API items once keeps components free of Instagram field names.

| Instagram | Schema v1 | Rule |
|---|---|---|
| `id` | `id` | Copy unchanged. |
| (none) | `source`, `status` | Constants: `"instagram"` and `"published"`. |
| `media_type` | `type` | `IMAGE` to `image`, `VIDEO` to `video`, `CAROUSEL_ALBUM` to `carousel`. |
| `media_product_type` | `format` | `REELS` gives `"reel"`. Any other value, or no value, gives `"post"`. |
| `thumbnail_url` or `media_url` | `thumbnailUrl` | `thumbnail_url` for a video, `media_url` for a photo; for a carousel, the same rule on the first slide. Required for image, video and carousel posts. |
| `permalink` | `url` | Link to the post on instagram.com. |
| `caption` | `text` | Empty string when absent. |
| `timestamp` | `publishedAt` | Insert the colon in the offset, then store ISO 8601 in UTC. |
| `children.data[]` | `media[]` | One entry per slide with `url` and `mime`. A single photo or video gives one entry from the item itself. |
| `like_count`, `comments_count` | `stats.likes`, `stats.comments` | Only when returned. |
| The whole item | `raw` | Keeps fields the schema does not name, such as `is_shared_to_feed`. |

Instagram sends no MIME type, and none of the fields above carries a pixel size. The converter derives `mime` from `media_type`; `aspectRatio` and `media[].width` stay unset unless you measure the files yourself.

lib/instagram-to-post.ts:

```ts
// Converts one /me/media item into an ElectricBlaze schema v1 post, or null when there is nothing to draw.
type IgItem = {
  id: string;
  media_type: "IMAGE" | "VIDEO" | "CAROUSEL_ALBUM";
  media_url?: string;     // absent for copyright-flagged media
  thumbnail_url?: string; // VIDEO only
};
type IgMedia = IgItem & {
  caption?: string;            // documented for Facebook Login only
  media_product_type?: string; // documented for Facebook Login only
  permalink: string;
  timestamp: string;           // "2026-09-12T07:41:00+0000"
  like_count?: number;
  comments_count?: number;
  children?: { data: IgItem[] };
};

const TYPE = { IMAGE: "image", VIDEO: "video", CAROUSEL_ALBUM: "carousel" } as const;
const coverOf = (m?: IgItem) => (m?.media_type === "VIDEO" ? m.thumbnail_url : m?.media_url);
// Instagram sends no MIME type: these two values are assumptions.
const toMedia = (m: IgItem) =>
  m.media_url ? [{ url: m.media_url, mime: m.media_type === "VIDEO" ? "video/mp4" : "image/jpeg" }] : [];

export function toPost(m: IgMedia) {
  const items: IgItem[] = m.media_type === "CAROUSEL_ALBUM" ? m.children?.data ?? [] : [m];
  const thumbnailUrl = coverOf(items[0]);
  if (!thumbnailUrl) return null;
  return {
    id: m.id,
    source: "instagram",
    type: TYPE[m.media_type],
    format: m.media_product_type === "REELS" ? "reel" : "post",
    status: "published",
    url: m.permalink,
    text: m.caption ?? "",
    media: items.flatMap(toMedia),
    thumbnailUrl,
    publishedAt: new Date(m.timestamp.replace(/([+-]\d{2})(\d{2})$/, "$1:$2")).toISOString(),
    stats: { likes: m.like_count, comments: m.comments_count },
    raw: m,
  };
}
```

Returning `null` is deliberate: schema v1 rejects an image, video or carousel post without `thumbnailUrl`, so a copyright-flagged item is dropped instead of breaking the grid.

## What ElectricBlaze data contains today

Two ElectricBlaze products expose Instagram data, and they are at different stages:

- **The widget** shows real posts today. Its data is the Graph API response as it comes, a `{"data": [...], "paging": {...}}` envelope. Each post has `id`, `caption`, `media_type`, `media_url`, `permalink`, `timestamp` and `username`. There is no `media_product_type`, so a reel is only a `VIDEO`, and no `children`, so carousel slides are not expanded. The demo feed also lacks `thumbnail_url`. We read this on 2026-09-17 from the demo feed and the renderer code.
- **The CLI** (0.1.2) writes demo posts that already follow schema v1, including `format: "reel"` and multi-item `media[]`. They are demo data. Whether real posts from the 0.2 JSON API will carry reel flags and carousel slides is not established yet.

Reel badges or swipeable carousels today need your own Graph API code with the expansion above, and reel badges also need a token that returns `media_product_type`.

## FAQ

### Why does /me/media return only ids?

The request has no `fields=` parameter. The media edge sends bare ids by default; list every field you draw, for example `fields=id,media_type,media_url,thumbnail_url,permalink,timestamp`.

### How do I get only reels from the Instagram API?

Keep items whose `media_product_type` equals `REELS`. The IG Media reference marks that field for Facebook Login only (checked 2026-09-18), so confirm your Instagram Login token returns it. `media_type` says `VIDEO` for reels and other videos alike.

### Why is thumbnail_url missing on photos?

It exists only on `VIDEO` items. Use `media_url` for an `IMAGE`, and the first slide for a `CAROUSEL_ALBUM`.

### How do I get every image in a carousel?

Request `children{media_type,media_url,thumbnail_url}` in the same call. Unexpanded, `children` returns ids, and each slide would need a request of its own.

### Which Graph API version should the URL use?

Meta's Instagram examples use v25.0, available until 2028-07-29, and v26.0 is the newest release (Graph API changelog, checked 2026-09-18). Pin one explicitly.

## Related pages

- [Feed schema v1](https://electricblaze.com/developer/instagram-feed/schema.html)
- [Media URL expired](https://electricblaze.com/developer/instagram-feed/media-url-expired.html)
- [Access tokens](https://electricblaze.com/developer/instagram-feed/access-token.html)
- [Basic Display alternatives](https://electricblaze.com/developer/instagram-feed/basic-display-api-alternative.html)
- [Feed not working](https://electricblaze.com/developer/instagram-feed/feed-not-working.html)
- [Next.js](https://electricblaze.com/developer/instagram-feed/nextjs.html)

---

ElectricBlaze, updated 2026-09-18. Source of this page: https://electricblaze.com/developer/instagram-feed/media-fields.html
