DEV Community

Davy
Davy

Posted on AI-assisted

How Facebook Page bulk deletion actually works with the Graph API

There is no Meta endpoint called “bulk delete Facebook Page posts.”

If you have ever searched for one, you already know the trap: Business Suite can delete a small batch, Activity Log is click-hell, and Chrome extensions pretend there is a bulk API by driving the website UI. Under the hood, official deletion is still one HTTP call per post.

DELETE https://graph.facebook.com/v21.0/{page-id}_{post-id}
Authorization: Bearer {page-access-token}
Enter fullscreen mode Exit fullscreen mode

A successful response is just:

{ "success": true }
Enter fullscreen mode Exit fullscreen mode

Ten thousand posts means ten thousand of those calls. That is the whole architecture.

What you can actually delete

With a Page access token and pages_manage_posts, Graph will delete regular Page posts the Page published:

  • status updates
  • photos that appear as feed items
  • Reels that appear in the feed
  • link shares

Scan the feed (GET /{page-id}/feed or /published_posts), filter by created_time, then DELETE each matching id.

Scopes that matter in practice:

  • pages_show_list
  • pages_manage_posts
  • pages_read_engagement
  • pages_read_user_content if you filter on comments/reactions

Missing them usually comes back as Graph error 10 or 200. Reconnect Login. Do not paper over it with a pasted user token.

What never deletes

This is the part most “bulk delete API” posts skip:

  • profile pictures and cover photos
  • story highlights
  • personal profile timeline posts (not a Page)
  • group posts
  • posts that are already gone (you get a failed DELETE, not a crash)

CSV export of ids/dates/links is a checklist, not a restore. Graph does not give you the image files back, and there is no undo.

Bulk is a loop, not a batch

A naive script looks like this:

for (const id of postIds) {
  const res = await fetch(`https://graph.facebook.com/v21.0/${id}`, {
    method: "DELETE",
    headers: { Authorization: `Bearer ${pageToken}` },
  });
  const body = await res.json();
  if (!body.success) {
    // log and continue — one failure must not abort 8,000 remaining ids
  }
}
Enter fullscreen mode Exit fullscreen mode

That script will work on a 50-post test Page and fall over on a real one. Meta rate-limits the Page and the app. “Done in seconds” is a lie once you leave a demo dataset.

Rate limits you will actually see

When Graph throttles you, the JSON error code is usually 4, 17, 32, or 613, plus messages like “too many calls” or “request limit reached.” Also read the headers:

  • X-Page-Usage
  • X-App-Usage

A workable policy we use in production:

  • usage around 80% → slow the loop
  • usage near 95%, or those error codes → pause, wait, resume
  • backoff that has survived real Pages: 5 min, 5 min, 10 min, then 15 min

Token errors are different. Code 190 means reconnect Facebook Login and start a new job for leftovers. Retrying the same expired token does nothing.

If you want the production notes (codes, headers, what we skip), I wrote up how Graph API page deletion works in production.

Do this on a server, not in a browser tab

Chrome extensions that “bulk delete” keep facebook.com open and click the UI. That breaks when Meta changes markup, and it is not the Pages API.

A Graph job should run on a worker:

  1. queue the post ids
  2. DELETE with pacing
  3. persist progress so a pause or a closed laptop does not lose the cursor
  4. stream a log to the browser if someone wants to watch

Closing the tab should not stop deletion. Staying on the page is optional.

Tokens

Use a Page access token, not a user token. Hold it in short-lived server memory/cache. Do not write raw tokens to your primary database. They expire on the order of an hour unless you exchange them, and you should have a “clear token when the job finishes” switch.

I work on PageCleanr, which wraps this loop (preview, CSV checklist, pause/resume). The Graph behavior above is Meta’s, not a product feature. If you are building your own cleaner, start with one DELETE, one Page, and the usage headers — then add the queue.

Top comments (0)