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

# Streaming and asynchronous jobs

> Upload progress with useConvertFile and handling of 202 (auto-async) in React Native.

# Streaming and asynchronous jobs

`@markpdf/react-native` does not expose `convertStream` — Fragment streaming (`ReadableStream`) has inconsistent support between the RN JS engine (Hermes/JSC) and RN versions. To show progress to the user, use the **upload** progress of `useConvertFile`, and for large documents consider [`pages`](/docs/api/parameters#pages) to request smaller ranges instead of response streaming.

## Upload progress with `useConvertFile`

```tsx theme={null}
import { useConvertFile } from "@markpdf/react-native";

function UploadScreen({ client, file }: { client: MarkpdfClient; file: LocalFile }) {
  const { convert, status, progress, markdown, error } = useConvertFile(client);

  return (
    <View>
      <Button title="Convertir" onPress={() => convert(file, { mode: "fast" })} />
      {status === "uploading" && <Text>Subiendo: {progress}%</Text>}
      {status === "converting" && <Text>Procesando…</Text>}
      {error && <Text>Error: {error.message}</Text>}
      {markdown && <Text>{markdown}</Text>}
    </View>
  );
}
```

`useConvertFile` uses `XMLHttpRequest` (available as global in React Native) instead of `fetch`, because `fetch` does not expose upload progress events in any JS runtime.

## Jobs due to saturation (202)

`convertLocalFile` and `convertFromUrl` handle `202` automatically with `autoPoll: true` (default):

```ts theme={null}
const markdown = await client.convertLocalFile({ uri, name });
// If the server responded 202, SDK already polled /jobs/{id} internally
```

### Poll manual

```ts theme={null}
const result = await client.convertLocalFile({ uri, name }, { autoPoll: false });

if (typeof result === "object" && "job_id" in result) {
  const job = await client.waitForJob(result.job_id, { pollIntervalMs: 3000, timeoutMs: 120_000 });
  if (job.status === "completed") {
    console.log(job.body);
  }
}
```

<Tip>
  In a mobile app with intermittent connection, consider an explicit `timeoutMs` in `waitForJob` to not leave the UI waiting indefinitely if the user loses signal.
</Tip>

<Warning>
  If the app goes to the background during the poll (the user exits the app), the `waitForJob` timer may be paused depending on the operating system. Upon returning to foreground, if `jobId` is still in effect (within \~1 hour), you can resume the poll by calling `getJob(jobId)` again.
</Warning>
