> For the complete documentation index, see [llms.txt](https://docs.layerlens.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.layerlens.ai/more-in-this-section-4/pattern-from-nextjs.md).

# Run an industry pattern from a Next.js app

Guide — implement an industry pattern end-to-end from a Next.js app, fusing pattern config + backend-call + browser UI.

The [industry patterns](/6.-build-wire-your-code/migration.md) describe the Stratix-side configuration. This guide shows how to implement one of them end-to-end inside a Next.js app — from a browser-side trigger to the pattern running against your data.

We'll use the [Telecom: customer-service pricing accuracy pattern](/4.2-industry-use-cases/pattern-10.md) as the example. The shape generalizes.

## Architecture

```
Browser (React)
 → POST /api/eval (Next.js route)
 → fetch stratix.layerlens.ai/api/v1/evaluations (X-API-Key)
 → poll evaluations/{id} until completed
 → return result to browser (or stream via SSE)
```

Critical: **the `LAYERLENS_STRATIX_API_KEY` lives only in the Next.js server**. Never `NEXT_PUBLIC_*`.

## Step 1: Configure the pattern (one-time, server-side)

Boot script: create the scorers and dataset the pattern needs. Run once.

`scripts/bootstrap-pricing-pattern.ts`:

```typescript
const headers = {
 "X-API-Key": process.env.LAYERLENS_STRATIX_API_KEY!,
 "Content-Type": "application/json",
};

// Pricing-citation JSON-schema scorer
const schemaScorer = await fetch("https://stratix.layerlens.ai/api/v1/scorers", {
 method: "POST",
 headers,
 body: JSON.stringify({
 name: "pricing-citation",
 type: "json_schema_validate",
 config: {
 schema: {
 type: "object",
 required: ["rate_card_row_id", "citation_ts"],
 properties: {
 rate_card_row_id: { type: "string" },
 citation_ts: { type: "string", format: "date-time" },
 },
 },
 },
 }),
});
const { id: schemaScorerId } = await schemaScorer.json();
console.log("Schema scorer:", schemaScorerId);
```

Save the returned scorer/judge IDs in your env or secrets manager.

## Step 2: Build the Next.js API route

`app/api/eval/route.ts`:

```typescript
import { NextRequest, NextResponse } from "next/server";

const HEADERS = {
 "X-API-Key": process.env.LAYERLENS_STRATIX_API_KEY!,
 "Content-Type": "application/json",
};

export async function POST(req: NextRequest) {
 const body = await req.json();
 // Authorize the caller (your auth layer here)

 // Create the evaluation against the user's dataset
 const created = await fetch("https://stratix.layerlens.ai/api/v1/evaluations", {
 method: "POST",
 headers: HEADERS,
 body: JSON.stringify({
 name: `cs-pricing-${Date.now()}`,
 model_id: body.model_id,
 dataset_id: body.dataset_id,
 scorers: [process.env.SCHEMA_SCORER_ID, process.env.NUMERIC_SCORER_ID],
 }),
 });
 const { id: evalId } = await created.json();

 return NextResponse.json({ evalId });
}
```

## Step 3: Stream progress to the browser via SSE

`app/api/eval/[id]/stream/route.ts`:

```typescript
import { NextRequest } from "next/server";

export async function GET(req: NextRequest, { params }: { params: { id: string } }) {
 const upstream = await fetch(
 `https://stratix.layerlens.ai/api/v1/evaluations/${params.id}/stream`,
 { headers: { "X-API-Key": process.env.LAYERLENS_STRATIX_API_KEY!, Accept: "text/event-stream" } }
 );

 return new Response(upstream.body, {
 headers: {
 "Content-Type": "text/event-stream",
 "Cache-Control": "no-cache",
 Connection: "keep-alive",
 },
 });
}
```

Stratix's SSE protocol is documented in [Streaming](/6.-build-wire-your-code/streaming.md).

## Step 4: Browser-side React component

`app/eval/page.tsx`:

```typescript
"use client";
import { useState } from "react";

export default function EvalPage() {
 const [status, setStatus] = useState<string>("");
 const [score, setScore] = useState<number | null>(null);

 const run = async () => {
 const r = await fetch("/api/eval", {
 method: "POST",
 headers: { "Content-Type": "application/json" },
 body: JSON.stringify({ model_id: "openai/gpt-4o", dataset_id: "pricing-regression-v1" }),
 });
 const { evalId } = await r.json();

 const events = new EventSource(`/api/eval/${evalId}/stream`);
 events.addEventListener("status", (e) => setStatus((e as MessageEvent).data));
 events.addEventListener("final", (e) => {
 const result = JSON.parse((e as MessageEvent).data);
 setScore(result.pass_rate);
 events.close();
 });
 };

 return (
 <main>
 <button onClick={run}>Run pricing-accuracy gate</button>
 <p>Status: {status}</p>
 {score !== null && <p>Pass rate: {(score * 100).toFixed(1)}%</p>}
 </main>
 );
}
```

The browser never sees the API key. The Next.js server proxies, authorizes, and streams.

## Step 5: Wire it into your CI

Same pattern, called from a CI runner instead of a browser:

```yaml
- name: Run pricing-accuracy gate
 run: |
 curl -X POST https://your-app.com/api/eval \
 -H "Content-Type: application/json" \
 -d '{"model_id":"openai/gpt-4o","dataset_id":"pricing-regression-v1"}'
```

Or skip your own backend entirely and call Stratix directly from the runner — see [Tutorial 3: Wire CI/CD quality gates](/6.-build-wire-your-code/03-cicd-gates.md).

## What you've built

* A pattern (Telecom: pricing accuracy) running against your model and dataset.
* A browser UI that triggers it without ever seeing an API key.
* SSE-based live progress to the browser.
* A reusable shape: swap the pattern, swap the dataset, swap the route name. Same architecture.

## Apply this to other patterns

* [Healthcare clinical decision support](/4.2-industry-use-cases/pattern.md) — replace `client.evaluations.create` with `client.trace_evaluations.create` and pass a trace-set filter
* [Insurance claims-triage agent](/4.2-industry-use-cases/pattern-3.md) — agentic evaluation; same proxy shape
* [Legal AI research citation verification](/4.2-industry-use-cases/pattern-2.md) — per-session trace eval; consider WebSocket instead of SSE if you need bidirectional

## See also

* [Calling Stratix from a backend](/more-in-this-section-4/calling-stratix-from-a-backend.md)
* [Concept: Streaming](/6.-build-wire-your-code/streaming.md)
* [REST API auth](/more-in-this-section-9/auth.md)
