# Providers

> Choose and configure the model provider that powers browser checks, or run checks without one in tests.

Configure the [provider](/reference/glossary/#provider) whose model drives browser checks. `@blopai/test` speaks the OpenAI chat-completions protocol. The collector and other Blop commands need no provider.

## Prerequisites

- An API key for one of the providers below.
- A model that supports tool calls and can call `finish_test` with a structured result.

## Set the provider

1. Set the provider, an explicit model and the key. The default provider is `openrouter`; there is no default model:

   ```bash
   export BLOP_AGENT_PROVIDER=openai
   export BLOP_AGENT_MODEL=gpt-5
   export BLOP_AGENT_API_KEY="$OPENAI_API_KEY"
   ```

2. Run a check:

   ```bash
   pnpm exec blop test run tests/catalog.blop.ts --base-url http://localhost:3000
   ```

Blop does not read provider key names such as `OPENAI_API_KEY` by itself: map the key into `BLOP_AGENT_API_KEY` or read it in your config. Keep keys in shell or CI secrets, never in checked-in files, goals or command history.

Precedence, highest first: the `--provider`, `--model` and `--api-key` flags; `provider`, `model` and `apiKey` in `blop.config.ts`; then `BLOP_AGENT_PROVIDER`, `BLOP_AGENT_MODEL` and `BLOP_AGENT_API_KEY`.

```ts
// blop.config.ts
import type { BlopConfig } from "@blopai/test";

export default {
  provider: "openai",
  model: "gpt-5",
  apiKey: process.env.BLOP_AGENT_API_KEY,
  baseUrl: "http://localhost:3000",
} satisfies BlopConfig;
```

## Supported providers

`--provider` accepts `openrouter`, `openai`, `groq`, `xai`, `mistral`, `cerebras`, `nvidia` and `ollama`.

Claude and Gemini models do not speak this protocol directly. Route them through OpenRouter instead of passing `anthropic` or `google`:

```bash
export BLOP_AGENT_PROVIDER=openrouter
export BLOP_AGENT_MODEL=anthropic/claude-sonnet-4-6
export BLOP_AGENT_API_KEY="$OPENROUTER_API_KEY"
```

`BLOP_AGENT_BASE_URL` points at a compatible gateway or proxy. The built-in `ollama` endpoint is `https://ollama.com/v1`; for a local Ollama server, set `BLOP_AGENT_BASE_URL=http://localhost:11434/v1`. This variable is the model endpoint; `--base-url` is the app under test.

## Check it worked

The check reaches its first browser action. A `No model configured` or `Missing API key` error, or another provider failure, ends with status `error`, which is not an app defect: read the error and tool events in `events.jsonl`, fix the setting and rerun the same check. See [Troubleshooting](/troubleshooting/#browser-check-fails-with-no-model-configured-or-missing-api-key).

## Reliability and cost of providers

Pin the provider and model in CI. After a model change, compare real outcomes and evidence rather than assuming the same behaviour. Precise goals and `--max-steps` stop runaway action loops. Retries and agent resumes add model calls; check the attempt and recovery fields in `results.json`.

## Run browser checks without a provider

To test the runner or your goal templates without model calls, pass a mock `agentStream` to `runBlopTests`:

```ts
import { runBlopTests, type BlopAgentStreamRunner } from "@blopai/test";

const mockStream: BlopAgentStreamRunner = async function* ({ nativeTools }) {
  const goto = nativeTools.find((t: any) => t.name === "browser_goto");
  const finish = nativeTools.find((t: any) => t.name === "finish_test");

  yield { event_type: "step_start", metadata: {} };
  await goto!.execute({ url: "https://example.com" });
  yield { event_type: "step_finish", metadata: {} };

  await finish!.execute({ status: "passed", reason: "page loaded" });
};

const result = await runBlopTests({
  specFiles: ["tests/example.blop.ts"],
  agentStream: mockStream,
});
```

No API key and no model calls. This tests runner behaviour, not a real model's reasoning or a live user journey.

## Next

- [Browser checks](/checks/)
- [Environment variables](/reference/environment/)
