Instagram feed not working: API errors, empty data and missing fields

Start from what you see, match it to a cause Meta documents, apply the fix. Each row names its source and the date we checked it.

At a glance

Status, checked 2026-09-18: requests to the Basic Display API have failed since 2024-12-04 (Meta developer blog, 2024-09-04, checked 2026-09-18); Instagram Login tokens stop working after 60 days unless refreshed (Meta: access_token reference, checked 2026-09-18); throttled calls return error 80002. For the ElectricBlaze widget, three checks on the page itself are listed at the end.

Use it when
a feed built on graph.instagram.com returns an error, an empty data array, posts without images or captions, or images that break some time after the page was built.
Do not use it when
the code still calls the Instagram Basic Display API. There is nothing to fix there; migrate as described in Basic Display alternative.
What the human does
the account owner logs in again after an expired or invalidated token, confirms the account is Business or Creator, and in Development mode accepts the Instagram Tester invite.
Next step
run the check script below with your token. It prints the HTTP status, the usage header, and the error code with its subcode, which is enough to find your row in the table.

Run one request and read all of it

Before changing code, make the call your feed makes and read the raw answer, headers included. The URL uses v25.0 because the Instagram examples from Meta do; v26.0 has been out since 2026-07-29 (Meta: Graph API changelog, checked 2026-09-18). Pin the version you tested and upgrade on purpose.

# -D - prints the response headers before the JSON body
curl -sS -D - "https://graph.instagram.com/v25.0/me/media?fields=id,media_type,media_url,permalink,timestamp&limit=5&access_token=$IG_ACCESS_TOKEN"

The same check in Node 18+, with a verdict instead of raw JSON:

scripts/check-instagram.mjs

// Usage: IG_ACCESS_TOKEN=... node scripts/check-instagram.mjs
const url = new URL("https://graph.instagram.com/v25.0/me/media");
url.searchParams.set("fields", "id,caption,media_type,media_url,permalink,timestamp");
url.searchParams.set("limit", "10");
url.searchParams.set("access_token", process.env.IG_ACCESS_TOKEN ?? "");

const res = await fetch(url);
const body = await res.json();
console.log("HTTP", res.status);
console.log("X-Business-Use-Case-Usage:", res.headers.get("x-business-use-case-usage") ?? "(absent)");

if (body.error) {
  const { type, code, error_subcode, message } = body.error;
  const hints = {
    "190/463": "token expired: the owner logs in again, then schedule refreshes",
    "190/460": "password changed: the owner logs in again",
    "190/467": "token invalid: check the stored value, then log in again",
  };
  console.log(type, code, error_subcode ?? "-", message);
  console.log("->", hints[`${code}/${error_subcode}`] ?? (code === 80002 ? "throttled: cache and call less often" : "see the table"));
} else {
  const items = body.data ?? [];
  console.log("items:", items.length, "| more pages:", Boolean(body.paging?.next));
  console.log("no media_url:", items.filter((m) => !m.media_url).map((m) => m.id));
  console.log("no caption field:", items.filter((m) => !("caption" in m)).length); // also counts posts with no caption
}

Symptom, cause, fix

Take the first row that matches. Rows that name a code or a message come from the error object; the others come from the shape of data or the setup.

Instagram API feed problems by symptom
SymptomCauseFix
OAuthException, code 190, error_subcode 463The long-lived token reached 60 days without a refreshThe owner logs in again; then schedule monthly refreshes (access tokens)
Code 190, subcode 460The account password changedThe owner logs in again
Code 190, subcode 467The token is invalid for another reasonCheck the stored value is complete and belongs to this app, then get a new one through Instagram Login
Every item has only idNo fields= parameter in the requestList the fields: fields=id,media_type,media_url,permalink,timestamp
data is [] although fields were requestedThe account has no posts, or the token belongs to another account than you thinkCall /v25.0/me?fields=username with the same token and compare the handle
One post has no media_urlMeta leaves it out for copyrighted or copyright-flagged media, for example a reel that uses licensed musicSkip the item or show a link to its permalink; it is not an error
No caption or media_product_typeBoth are marked as Facebook Login only in the IG Media referenceTest with your token; render without them when absent
Images answer 403 "URL signature expired"The signed link passed the expiry encoded in its oe parameterFetch fresh URLs before serving cached HTML (media URL expired)
Error 80002, high values in X-Business-Use-Case-UsageThe app used up its Instagram Platform call budgetCache on the server and call once per refresh interval, not once per page view
"Insufficient developer role"Development mode, and the account lacks the Instagram Tester role (reported by a secondary source)Invite the account as an Instagram Tester; the owner accepts under Settings, Apps and websites, Tester invites in Instagram
Code written before December 2024 fails on every callIt targets the Instagram Basic Display API, shut down on 2024-12-04Move to the Instagram API with Instagram Login (Basic Display alternative)
The authorize URL still requests business_basicThat scope value was deprecated on 2025-01-27Request instagram_business_basic
The owner's account is personalOnly professional accounts are servedThe owner switches it to Business or Creator in the Instagram app

Sources: Meta: Graph API error handling, checked 2026-09-18; Meta: get started with Instagram Login, checked 2026-09-18; Meta: IG Media reference, checked 2026-09-18; verbb/social-feeds issue 21 (2026-01), checked 2026-09-18 (secondary); Meta: rate limiting, checked 2026-09-18; Chatwoot docs on Instagram Business Login, checked 2026-09-18 (secondary); Meta developer blog, 2024-09-04, checked 2026-09-18; Meta: Instagram API with Instagram Login, checked 2026-09-18; Meta: Instagram Platform overview, checked 2026-09-18.

Reading the error object

Every failed call carries an error object. Branch on code and error_subcode; the message text embeds timestamps and varies from call to call.

An expired long-lived token (example values)

{
  "error": {
    "message": "Error validating access token: Session has expired on Saturday, 12-Sep-26 09:15:42 PDT. The current time is Friday, 18-Sep-26 03:02:11 PDT.",
    "type": "OAuthException",
    "code": 190,
    "error_subcode": 463,
    "fbtrace_id": "AbCdEfGhIjK_example"
  }
}
  • Code 190 means the token is unusable: 463 expired, 460 password changed, 467 invalid (Meta: Graph API error handling, checked 2026-09-18). All three end with the owner logging in again.
  • Do not branch on type alone. OAuthException also shows up on errors that have nothing to do with tokens.
  • Log fbtrace_id with the time of the call. It identifies the request if you ever report the problem to Meta.

Empty or partial data

An empty or short feed with HTTP 200 carries no error object. Three causes explain it:

  1. No fields requested. Without fields=, the media edge returns each item as an id and nothing more (Meta: get started with Instagram Login, checked 2026-09-18). The renderer has no image to draw.
  2. Another account, or no posts. A token belongs to exactly one account. Ask /me?fields=username which one before debugging the rest.
  3. Pagination stopped early. A page can hold fewer items than limit, so a short page is not the end of the feed; stop only when paging.next is absent (Meta: Graph API paginated results, checked 2026-09-18).

A missing field on one item is often expected. media_url is omitted when the media contains copyrighted material or was flagged for it (Meta: IG Media reference, checked 2026-09-18). thumbnail_url exists only on VIDEO items (Meta: IG Media reference, checked 2026-09-18). Carousel children come back as bare ids until you expand them as children{media_type,media_url,thumbnail_url} (Meta: IG Media children, checked 2026-09-18).

Available for Instagram API with Facebook Login only

Many tutorials request caption from graph.instagram.com regardless. We make no promise in either direction: test with your own token and keep the layout intact when the field is absent. Media fields covers each field in detail.

Throttling: error 80002

Instagram Platform calls, messaging aside, share a budget of 4800 × the number of impressions per 24 hours (Meta: rate limiting, checked 2026-09-18). Past it, calls fail with 80002. The X-Business-Use-Case-Usage response header reports how much of the budget is used, so log it on every call and slow down before the limit, not after.

Codes 4, 17 and 613 are general Graph API limits. Back off on them too, but for Instagram Platform calls look for 80002 first.

One call per refresh window is enough for a feed. Serve page views from a server-side cache; a browser calling Instagram directly would also expose the token.

Checks for the ElectricBlaze widget

For the ElectricBlaze embed, the token rows above do not apply to your site. Three page-side checks do:

  1. The id is the container's first class. The loader takes the widget id from the first class and ignores the rest, so class="electricblaze-id-w42 feed" mounts and class="feed electricblaze-id-w42" does not.
  2. The Content Security Policy lets the widget through. script-src must allow https://s.electricblaze.com. connect-src must allow https://api.electricblaze.com, https://proxy.electricblaze.com, which serves the data of connected accounts, and https://s.electricblaze.com for demo data. The browser console names any other blocked host and directive.
  3. The state class tells you where it stopped. The loader sets electricblaze-state-loading, -mounting, -mounted or -error on the container. A container left in electricblaze-state-error did not mount: check the widget id and the /v1/package request in the network panel.
Content-Security-Policy: script-src 'self' https://s.electricblaze.com; connect-src 'self' https://api.electricblaze.com https://proxy.electricblaze.com https://s.electricblaze.com; img-src 'self' https: data:

The loader also picks up containers added after page load, such as after a client-side route change, and ignores a second copy of widget.js. What the widget displays once a Free plan passes 1000 views in a month is not established yet; this page will say when it is.

FAQ

Why does /me/media return only ids?

The request has no fields= parameter. Without it the media edge returns every item as a bare id. Add fields=id,media_type,media_url,permalink,timestamp.

What does OAuthException 190 with error_subcode 463 mean?

The access token expired. Tokens from Instagram Login last 60 days and cannot be refreshed after that, so the account owner has to log in again.

Why is caption missing from the Instagram API response?

The IG Media reference marks caption as available with Facebook Login only (Meta: IG Media reference, checked 2026-09-18). Test with your token and render posts without a caption when the field is absent.

Why do Instagram images stop loading some time after the page was built?
media_url is a signed link whose oe parameter holds the expiry; after it the server answers 403 "URL signature expired" (verbb/social-feeds issue 21 (2026-01), checked 2026-09-18, secondary). Meta publishes no lifetime, so fetch fresh URLs before serving cached pages.
Does the Instagram Basic Display API still work?

No. Meta shut it down on 2024-12-04, and every request to it fails. The replacement is the Instagram API with Instagram Login, for Business and Creator accounts.

What is Instagram API error 80002?

The Instagram Platform throttling error. The budget is 4800 × impressions per 24 hours, and the X-Business-Use-Case-Usage header shows how close you are. Cache responses on the server.