> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/unjs/ofetch/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks

> Lifecycle hooks for intercepting and handling fetch requests

## Overview

The `FetchHooks` interface provides lifecycle hooks that allow you to intercept and handle different stages of the fetch request process.

## Type Signature

```typescript theme={null}
export interface FetchHooks<T = any, R extends ResponseType = ResponseType> {
  onRequest?: MaybeArray<FetchHook<FetchContext<T, R>>>;
  onRequestError?: MaybeArray<FetchHook<FetchContext<T, R> & { error: Error }>>;
  onResponse?: MaybeArray<
    FetchHook<FetchContext<T, R> & { response: FetchResponse<T> }>
  >;
  onResponseError?: MaybeArray<
    FetchHook<FetchContext<T, R> & { response: FetchResponse<T> }>
  >;
}

type FetchHook<C extends FetchContext = FetchContext> = (
  context: C
) => MaybePromise<void>;

type MaybePromise<T> = T | Promise<T>;
type MaybeArray<T> = T | T[];
```

## Hooks

### onRequest

<ParamField path="onRequest" type="FetchHook<FetchContext<T, R>> | FetchHook<FetchContext<T, R>>[]">
  Called before the request is sent. Use this to modify request options, add headers, or log requests.
</ParamField>

**Context Parameters:**

<ParamField path="context.request" type="FetchRequest">
  The request URL or Request object
</ParamField>

<ParamField path="context.options" type="ResolvedFetchOptions<R>">
  Resolved request options that will be used for the fetch
</ParamField>

<ParamField path="context.response" type="FetchResponse<T> | undefined">
  Undefined at this stage
</ParamField>

<ParamField path="context.error" type="Error | undefined">
  Undefined at this stage
</ParamField>

**Example:**

```typescript theme={null}
await ofetch('/api/users', {
  onRequest({ request, options }) {
    console.log('Fetching:', request)
    options.headers.set('X-Custom-Header', 'value')
  }
})
```

### onRequestError

<ParamField path="onRequestError" type="FetchHook<FetchContext<T, R> & { error: Error }> | FetchHook<FetchContext<T, R> & { error: Error }>[]">
  Called when the request fails to execute (network error, timeout, etc.). Does not include HTTP error responses (4xx, 5xx) - use `onResponseError` for those.
</ParamField>

**Context Parameters:**

<ParamField path="context.request" type="FetchRequest">
  The request URL or Request object
</ParamField>

<ParamField path="context.options" type="ResolvedFetchOptions<R>">
  Request options used for the fetch
</ParamField>

<ParamField path="context.error" type="Error" required>
  The error that occurred during the request
</ParamField>

<ParamField path="context.response" type="FetchResponse<T> | undefined">
  Undefined for network errors
</ParamField>

**Example:**

```typescript theme={null}
await ofetch('/api/users', {
  onRequestError({ request, error }) {
    console.error('Request failed:', request, error)
    // Log to error tracking service
    errorTracker.log(error)
  }
})
```

### onResponse

<ParamField path="onResponse" type="FetchHook<FetchContext<T, R> & { response: FetchResponse<T> }> | FetchHook<FetchContext<T, R> & { response: FetchResponse<T> }>[]">
  Called after a successful response is received (any status code). Use this to log responses, modify response data, or handle specific status codes.
</ParamField>

**Context Parameters:**

<ParamField path="context.request" type="FetchRequest">
  The request URL or Request object
</ParamField>

<ParamField path="context.options" type="ResolvedFetchOptions<R>">
  Request options used for the fetch
</ParamField>

<ParamField path="context.response" type="FetchResponse<T>" required>
  The fetch response object with parsed data in `_data` property. See [FetchResponse](/api/types/response-types#fetchresponse).
</ParamField>

<ParamField path="context.error" type="Error | undefined">
  Undefined for successful responses
</ParamField>

**Example:**

```typescript theme={null}
await ofetch('/api/users', {
  onResponse({ response }) {
    console.log('Response status:', response.status)
    console.log('Response data:', response._data)
    
    // Modify response data
    if (response._data) {
      response._data.timestamp = Date.now()
    }
  }
})
```

### onResponseError

<ParamField path="onResponseError" type="FetchHook<FetchContext<T, R> & { response: FetchResponse<T> }> | FetchHook<FetchContext<T, R> & { response: FetchResponse<T> }>[]">
  Called when the response has an HTTP error status (4xx or 5xx). Use this to handle specific error cases before the error is thrown.
</ParamField>

**Context Parameters:**

<ParamField path="context.request" type="FetchRequest">
  The request URL or Request object
</ParamField>

<ParamField path="context.options" type="ResolvedFetchOptions<R>">
  Request options used for the fetch
</ParamField>

<ParamField path="context.response" type="FetchResponse<T>" required>
  The fetch response object with error status. See [FetchResponse](/api/types/response-types#fetchresponse).
</ParamField>

<ParamField path="context.error" type="Error | undefined">
  May contain the error that will be thrown
</ParamField>

**Example:**

```typescript theme={null}
await ofetch('/api/users', {
  onResponseError({ request, response }) {
    console.error(
      `Error ${response.status}: ${request}`
    )
    
    // Handle specific status codes
    if (response.status === 401) {
      // Redirect to login
      window.location.href = '/login'
    }
  }
})
```

## Multiple Hooks

You can provide multiple hooks as an array. They will be called in order:

```typescript theme={null}
await ofetch('/api/users', {
  onRequest: [
    ({ options }) => {
      options.headers.set('X-Request-ID', generateId())
    },
    ({ request }) => {
      console.log('Request:', request)
    }
  ],
  onResponse: [
    ({ response }) => {
      console.log('Status:', response.status)
    },
    ({ response }) => {
      logAnalytics(response)
    }
  ]
})
```

## Async Hooks

Hooks can be asynchronous:

```typescript theme={null}
await ofetch('/api/users', {
  async onRequest({ options }) {
    const token = await getAuthToken()
    options.headers.set('Authorization', `Bearer ${token}`)
  },
  async onResponse({ response }) {
    await saveToCache(response._data)
  }
})
```

## Global Hooks

Set hooks globally when creating a fetch instance:

```typescript theme={null}
const apiFetch = ofetch.create({
  onRequest({ options }) {
    options.headers.set('X-Client-Version', '1.0.0')
  },
  onResponseError({ response }) {
    if (response.status === 401) {
      redirectToLogin()
    }
  }
})
```

## Type Parameters

<ParamField path="T" type="any" default="any">
  The expected type of the response data
</ParamField>

<ParamField path="R" type="ResponseType" default="ResponseType">
  The response type. See [ResponseType](/api/types/response-types#responsetype).
</ParamField>

## Related

* [FetchContext](/api/types/response-types#fetchcontext) - Context object passed to hooks
* [FetchResponse](/api/types/response-types#fetchresponse) - Response interface
* [FetchOptions](/api/options/fetch-options) - Complete options interface
