> ## Documentation Index
> Fetch the complete documentation index at: https://docs.filerouter.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Compare Document Parsing Across Multiple Providers

> Run one document through multiple providers at once with compare(). Evaluate output quality side by side across LlamaParse, Mistral OCR, and Datalab.

`router.compare(input, options)` sends one document to multiple providers at the same time and returns a single `CompareResult` containing each provider's output. This is the fastest way to evaluate which provider performs best on your document type before committing to one in production. Both `FileRouter` (BYOK) and `FileRouterClient` (hosted) expose the same `compare()` signature.

## How compare() resolves the input

FileRouter resolves the input document **once** before dispatching to providers. If you pass a `ReadableStream`, it is consumed a single time and converted to replayable bytes so every provider receives identical data. This also means you can safely pass a `File` or `Blob` without worrying about the stream being exhausted.

## CompareOptions

<ParamField body="providers" type="Array<string>">
  The IDs of the providers you want to compare (e.g. `['llamaparse', 'mistral-ocr']`). When omitted, the router runs all configured providers concurrently.
</ParamField>

<ParamField body="outputs" type="Array<string>" default="['markdown']">
  The output types to request from each provider. Available values match `ParseOptions`: `'chunks'`, `'html'`, `'images'`, `'json'`, `'markdown'`, `'metadata'`, `'pages'`, `'tables'`, `'text'`. A provider that does not support a requested output will appear in the result with `status: 'unsupported'` rather than failing the whole comparison.
</ParamField>

<ParamField body="pages" type="Array<number>">
  One-based page numbers to process. When omitted, all pages are processed. The router translates these into each provider's native representation.
</ParamField>

<ParamField body="providerOptions" type="ProviderParseOptions">
  Namespaced provider-specific options. Only the options matching a given provider's key are forwarded to that provider — settings for one provider are never sent to another.

  ```ts theme={null}
  providerOptions: {
    llamaparse: { tier: 'premium' },
    'mistral-ocr': { /* Mistral-specific fields */ },
  }
  ```
</ParamField>

<ParamField body="includeRaw" type="boolean" default="false">
  Set to `true` to include each provider's complete native response in its `ParseResult.raw` field.
</ParamField>

<ParamField body="timeoutMs" type="number" default="600000">
  Maximum time in milliseconds to wait for all providers to complete. Defaults to 10 minutes.
</ParamField>

<ParamField body="signal" type="AbortSignal">
  An `AbortSignal` for cancelling the operation.
</ParamField>

## CompareResult

The result contains top-level metadata about the comparison and a `providers` array with one entry per provider.

<ResponseField name="providers" type="Array<CompareProviderResult>">
  An array of per-provider results, one entry per provider that was run.

  <Expandable title="CompareProviderResult fields">
    <ResponseField name="provider" type="string">
      The provider ID (e.g. `'llamaparse'`).
    </ResponseField>

    <ResponseField name="status" type="'parsed' | 'failed' | 'unsupported'">
      Whether the provider succeeded, failed, or reported the requested output as unsupported.
    </ResponseField>

    <ResponseField name="result" type="ParseResult">
      The full `ParseResult` for this provider. Present only when `status` is `'parsed'`. See [ParseResult](/sdk/parse#parseresult) for the full shape.
    </ResponseField>

    <ResponseField name="error" type="object">
      An error summary with `message` and optional `code`. Present only when `status` is `'failed'` or `'unsupported'`.
    </ResponseField>

    <ResponseField name="durationMs" type="number">
      How long this provider took to respond, in milliseconds.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="outputs" type="Array<string>">
  The output types that were requested for this comparison run.
</ResponseField>

<ResponseField name="input" type="string">
  A description of the input document (e.g. the filename or URL).
</ResponseField>

<ResponseField name="timing" type="object">
  Timing information for the overall comparison with `startedAt`, `completedAt` (ISO 8601 strings), and `durationMs`.
</ResponseField>

## Complete example

The example below compares LlamaParse and Mistral OCR on the same PDF and prints the Markdown output from each provider that succeeded.

```ts compare-providers.ts theme={null}
import { FileRouter } from '@file_router/sdk'
import { llamaparse } from '@file_router/sdk/llamaparse'
import { mistralOcr } from '@file_router/sdk/mistral'

const router = new FileRouter({
  providers: {
    llamaparse: llamaparse(),
    'mistral-ocr': mistralOcr(),
  },
})

const comparison = await router.compare('https://example.com/invoice.pdf', {
  providers: ['llamaparse', 'mistral-ocr'],
  outputs: ['markdown'],
})

console.log(`Comparison took ${comparison.timing.durationMs}ms total`)
```

### Iterating over the result

```ts iterate-compare-result.ts theme={null}
for (const entry of comparison.providers) {
  if (entry.status === 'parsed' && entry.result) {
    console.log(`\n--- ${entry.provider} (${entry.durationMs}ms) ---`)
    console.log(entry.result.outputs.markdown)
  } else {
    console.warn(
      `${entry.provider} ${entry.status}: ${entry.error?.message}`
    )
  }
}
```

<Warning>
  A `compare()` call counts as one parse job per provider against your usage. Running three providers on a 50-page document counts as three 50-page parse jobs.
</Warning>

<Tip>
  When you need to pinpoint which provider caused a problem, check `error.code` on the failed `CompareProviderResult` entry. You can also use the `providerId` field on a `FileRouterError` if you catch one from a standalone `parse()` call — see [Errors](/sdk/errors) for details.
</Tip>
