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

# Data flow

> Where prompt content and metadata travel for each PromptGuard surface (proxy, Guard API, SDK auto-instrumentation, Shadow desktop agent, hosted inference), what is stored where, and how Hybrid and Air-gapped change it.

This page draws one diagram per surface. On every arrow, **content** means
prompt or response text (or text extracted from an attachment). **Metadata**
means decisions, threat types, counts, identifiers and timings, with no prompt
text. What a stored security event contains, and how long it is kept, is
described in [Compliance & Security](https://docs.promptguard.co/security/compliance.md#data-handling).

## What is stored where (Cloud)

| Store | Where it runs | What it holds |
| - | - | - |
| PromptGuard API | Google Cloud Run, us-east4 | Nothing at rest. Prompts and responses are scanned in memory |
| Database | Supabase (Postgres), AWS us-east-1 | Accounts, projects, API key digests, encrypted provider keys, security events (metadata, plus a masked preview of at most 500 characters unless previews are off), audit log |
| Hugging Face router | Hugging Face and the inference provider it routes to | Receives the text being scanned when a scan reaches the machine-learning or LLM-judge tiers. Listed on [subprocessors](https://promptguard.co/subprocessors) |
| Your LLM provider | Wherever your provider runs | Receives your prompts, under your agreement with that provider |

## Proxy

Your application sends its LLM request to PromptGuard in place of the
provider. PromptGuard scans it, forwards an allowed request to your provider,
and scans the response on the way back.

```mermaid theme={"system"}
graph LR
    App[Your app] -->|content| PG[PromptGuard API<br/>us-east4]
    PG -->|content, if a scan reaches<br/>the ML or LLM-judge tier| HF[Hugging Face router]
    HF -->|scores: metadata| PG
    PG -->|content, if allowed or redacted| LLM[Your LLM provider]
    LLM -->|content| PG
    PG -->|content| App
    PG -->|metadata + masked preview| DB[(Supabase<br/>security events)]
```

* Pattern and heuristic detection runs inside the API. Classifiers with local
  weights run in-process first and fall back to the Hugging Face router.
  The LLM judges run on the router (`backend/api/shared/security/inference_mode.py`).
* A blocked request never reaches your provider.
* A project with **zero retention** on, or an organization with previews off,
  stores the event without the masked preview.
* Webhooks and [SIEM export](https://docs.promptguard.co/integrations/siem-export.md) send event records to
  destinations you configure.

## Guard API and SDK auto-instrumentation

With the Guard API, PromptGuard scans text and returns a verdict. It never
calls your provider. The SDKs' auto-instrumentation (for example the Python
SDK's `promptguard.init()`) patches your LLM client so that each call asks the
Guard API first, then goes to your provider **directly**, with your own
provider key.

```mermaid theme={"system"}
graph LR
    App[Your app + SDK] -->|content: messages to scan| PG[PromptGuard Guard API<br/>us-east4]
    PG -->|content, if a scan reaches<br/>the ML or LLM-judge tier| HF[Hugging Face router]
    PG -->|verdict: metadata| App
    App -->|content + your provider key,<br/>if the verdict allows| LLM[Your LLM provider]
    LLM -->|response content| App
    App -.->|response content, only with<br/>scan_responses=True| PG
    PG -->|metadata + masked preview| DB[(Supabase<br/>security events)]
```

* PromptGuard never sees your provider key on this path.
* Responses reach PromptGuard only if you turn on response scanning.
* If the Guard API cannot be reached, the SDK fails open by default and the
  call goes to your provider unscanned. `fail_open=False` blocks instead.

## Shadow desktop agent

The agent inspects prompts to AI tools **on the device**. It masks what its
on-device detectors find before anything leaves, and the engine decides the
verdict. The full detail, including every setting, is in
[Shadow AI privacy & data handling](https://docs.promptguard.co/shadow-ai/privacy-data-handling.md).

```mermaid theme={"system"}
graph LR
    User[Employee's AI tool] -->|content| Agent[Shadow agent<br/>on the device]
    Agent -->|masked content + device findings,<br/>or metadata only| Engine[PromptGuard engine<br/>Cloud, Hybrid or Air-gapped]
    Engine -->|verdict: metadata| Agent
    Agent -->|content, as the verdict allows| Vendor[AI vendor]
    Agent -->|check-in: counts, no prompt| Engine
    Engine -->|metadata + masked preview| DB[(Security events)]
```

* **Masked by default.** On PromptGuard's cloud engine the agent sends the
  prompt with every on-device finding replaced by a placeholder. On any other
  engine it defaults to `metadata_only`, which sends no prompt content at all.
  Raw prompt text is never sent.
* **Device findings** are a category and a count, never a value.
* With the on-device pre-filter set to `escalate` or `local`, prompts it
  resolves on the device are not sent to the engine at all.
* The engine is the same as on the other surfaces. A cloud engine can call the
  Hugging Face router as in the proxy diagram. Air-gapped does not.

## Self-hosted: Hybrid and Air-gapped

Self-hosted, the engine runs on your servers. These settings decide what
leaves them. Defaults are from `backend/api/config.py` and
`backend/api/shared/security/inference_mode.py`.

| | Hybrid (`DEPLOYMENT_MODE=data_plane`) | Air-gapped (`DEPLOYMENT_MODE=airgap`) |
| - | - | - |
| Events sent to PromptGuard | Yes, to our dashboard (control plane) | No. Your own dashboard stores them |
| `FORWARD_MODE` | `metadata` by default: decision, threat type, counts, identifiers. `content` adds the masked preview and the engine's free-text reason | Not used |
| `STORE_PREVIEWS` | On by default | Off by default |
| `ML_INFERENCE_MODE` | `api` by default: calls the Hugging Face router with the `HUGGINGFACE_API_TOKEN` you configure. Set `local` to keep inference on your servers | `local` by default: nothing reaches hosted inference |
| Policies | Pulled from our control plane | Managed in your dashboard |
| Licence | Renewed through a daily check-in | Installed by hand; no check-in |
| Your LLM provider | Called from your servers | Called from your servers |

```mermaid theme={"system"}
graph LR
    App[Your app] -->|content| Engine[Engine on your servers]
    Engine -->|content| LLM[Your LLM provider]
    Engine -->|Hybrid: metadata by default,<br/>masked preview only with FORWARD_MODE=content| CP[PromptGuard control plane]
    CP -->|policies| Engine
    Engine -.->|content, only with ML_INFERENCE_MODE=api| HF[Hugging Face router]
    Engine -->|Air-gapped: events stay local| LocalDB[(Your database)]
```

What each mode sends to us, capability by capability, is in
[Self-Host vs Cloud](https://docs.promptguard.co/production/self-host-vs-cloud.md).

## Next steps

> [card] [Shadow AI privacy](https://docs.promptguard.co/shadow-ai/privacy-data-handling.md)
>
> What the agent inspects, logs and sends

> [card] [Compliance](https://docs.promptguard.co/security/compliance.md)
>
> Certifications, data handling and retention

> [card] [Self-host vs Cloud](https://docs.promptguard.co/production/self-host-vs-cloud.md)
>
> What differs when you run the engine yourself


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.