# Processing & scanning (/docs/guides/processing-and-scanning)



<ComponentPreview name="scan-states" />

A browser can't scan files for malware, and UploadCN doesn't pretend to. What it gives
you is states your backend controls.

<Callout title="Looking for built-in scanning?">
  `createUploadRoute` can scan every upload with ClamAV, VirusTotal or your own service
  before it completes. See [Virus scanning](/docs/guides/virus-scanning). This page covers
  driving the states yourself, for background jobs and webhooks. For text recognition, see
  [OCR](/docs/guides/ocr).
</Callout>

<Flow label="Server-side states" steps="[&#x22;Uploading&#x22;, &#x22;Processing&#x22;, { label: &#x22;Scanning&#x22;, highlight: true }, &#x22;Success&#x22;]" branches="[{ from: &#x22;Scanning&#x22;, to: &#x22;Rejected&#x22;, note: &#x22;the scanner found a problem&#x22; }]" />

## With `process` [#with-process]

`process` runs after the adapter stored the file. Move between states with `setStatus`;
throw an `UploadError` with code `"rejected"` to reject.

```ts
import { UploadError } from "@uploadcn/core"

<Upload
  adapter={adapter}
  process={async (item, { setStatus, signal, result }) => {
    setStatus("scanning")
    const verdict = await waitForScan(result.key, { signal }) // poll, SSE, or websocket
    if (verdict === "infected") {
      throw new UploadError("Malware detected", { code: "rejected" })
    }
    return { ...result, scanned: true } // becomes item.result
  }}
/>
```

## From outside (webhooks, realtime) [#from-outside-webhooks-realtime]

When results arrive through another channel, drive the item directly:

```ts
uploader.update(id, { status: "scanning" })
uploader.update(id, { status: "success", result })
uploader.update(id, { status: "rejected", error: "Malware detected" })
```

## Server side [#server-side]

For inline scanning, pass `scan` to `createUploadRoute` ([Virus scanning](/docs/guides/virus-scanning)).
For background scanning, kick it off in `onUploadComplete` (enqueue a job, or rely on your
storage provider's scanning integration) and expose the verdict to the client. Until a file is
approved, keep it out of public access, for example, upload to a quarantine prefix and
copy approved files to their final location.
