FID retired Nov 1: keep a Sume generate button responsive
Vercel Speed Insights drops First Input Delay on November 1. A Sume generate button stays responsive if it submits async, gets a 202 and polls via your server.

Vercel's October 1, 2026 changelog says Speed Insights deprecates First Input Delay on November 1. Whatever metric replaces it in your dashboard, a button that starts a Sume render should answer the click immediately. Submit with the default async mode, which returns 202 and a job id, then poll for the result.
The Vercel change
The Vercel changelog, read on 2026-10-03, announces the deprecation. This post does not say which metric replaces it or how your scores will move; read Vercel's note for that.
Why a generate button feels slow
Video, avatar-video and face-swap jobs routinely outlast the 30 second wait budget. sync and subscribe hold the HTTP request for at most 30 seconds, then hand back the job anyway. The docs recommend async or webhook for anything that can outlast that, which is most video work.
| Mode | Server blocks | Use when |
|---|---|---|
| async (default) | No, returns 202 | Polling from a UI |
| sync | Up to 30 s | Short image jobs |
| subscribe | Same as sync | Ported queue clients |
| webhook | No, returns 202 | Server-to-server completion |
Route handlers that never block
Keep the API key on the server. One handler submits and returns the job id, and a second returns status. The UI polls your status route with backoff and shows progress instead of freezing.
// app/api/render/route.ts
export async function POST(req: Request) {
const { prompt, clientKey } = await req.json();
const r = await fetch("https://api.sume.com/v1/videos", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SUME_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": clientKey,
},
body: JSON.stringify({ model: "sume/auto", prompt }),
});
const job = await r.json();
return Response.json({ id: job.id }, { status: r.status });
}
// app/api/render/[id]/route.ts
export async function GET(_: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const r = await fetch(`https://api.sume.com/v1/jobs/${id}/status`, {
headers: { Authorization: `Bearer ${process.env.SUME_API_KEY}` },
});
return Response.json(await r.json(), { status: r.status });
}Polling rules from the docs
Stop polling on completed, failed or canceled, use exponential backoff, and honor next_poll_after_seconds when it is present. Do not resubmit the paid request because the browser tab closed. Generate the clientKey once per user intent so a double click returns the original job.
Sources
Related posts
More in Developers
- Split a narration script by model character limit: Python
ElevenLabs lists a 40,000 character limit for Flash v2.5 and 10,000 for v4 and v4 Turbo. A Python splitter that cuts on sentences, with a concat step on Sume.
- Sume bulk items ignore on_active_run skip: allow is forced
Setting on_active_run skip or reject on a Sume bulk item does not stall the window, because the bulk controller runs every item with allow. What that changes.
- Count Sume bulk webhooks to know the queue is done, and the trap
A Sume bulk queue has no webhook, so some teams count per-item deliveries. Canceled and skipped runs never deliver, so a pure counter can hang. Use a hybrid.
- Sume image 400s name the valid values: retry in code
Sume's Image API 400 bodies carry details.supported, allowed, min and max. A tested error table and a small function that retries with a valid value.
Written by Sume