Skip to content

Plugins & interceptors ​

Built-in plugins ​

PluginFactory (tanstack-fetch/plugins)Role
tracecreateTraceInterceptor()Adds x-request-id
ssr-forwardcreateSsrForwardInterceptor()Forwards cookies / auth on the server
retry-idempotentcreateRetryIdempotentInterceptor()Retries safe methods on retryable statuses
sse-resumecreateSseResumeInterceptor()Drops heartbeats; sends Last-Event-ID on reconnect
ts
import { createFetch } from 'tanstack-fetch'
import {
  createRetryIdempotentInterceptor,
  createSseResumeInterceptor,
  createSsrForwardInterceptor,
  createTraceInterceptor,
} from 'tanstack-fetch/plugins'

createFetch({
  interceptors: [
    createTraceInterceptor(),
    createSsrForwardInterceptor(),
    createRetryIdempotentInterceptor(),
    createSseResumeInterceptor(),
  ],
})

tanstack-fetch/sse, /live, /trpc and framework providers also accept the string shorthand plugins: ['trace', 'ssr-forward', 'retry-idempotent', 'sse-resume'].

Named interceptors ​

ts
api.use('locale', {
  order: 25,
  onRequest: (context) => {
    context.request.headers.set('accept-language', 'fa')
    return { action: 'continue', context }
  },
})

api.eject('locale')

Interceptor hooks ​

HookWhen
onRequestBefore every request, and before every SSE / WebSocket / WebTransport / NDJSON connect (auth, headers)
onResponse / onResponseErrorHTTP response (also api.stream headers)
onRequestErrorNetwork failure
onSseOpen / onSseEvent / onSseError / onSseReconnect / onSseCloseapi.sse lifecycle
onLiveOpenapi.ws / api.transport connected, or api.stream response opened
onLiveMessageEvery live message: context.message.direction is 'in' or 'out'
onLiveCloseOnce per connection; context.error is set when it ended abnormally

context.meta.transport tells live connections apart: 'websocket' | 'webtransport' | 'ndjson'.

ts
api.use('live-log', {
  onLiveMessage: (context) => {
    console.log(context.meta.transport, context.message.direction, context.message.data)
    return { action: 'continue', context }
  },
})

Per-request control ​

ts
await api.get('/admin', {
  interceptors: {
    use: [extraInterceptor],
    eject: ['retry-idempotent'],
  },
})

Match filters ​

Interceptors can match on operation, method, pathPrefix, or status.

Decision actions: continue · skip · retry · short-circuit · drop.

See Refresh token recipe for a real 401 → refresh → retry interceptor.

MIT Licensed · Created by Mohammad Garmabi · Not an official TanStack package