> 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

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)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.layerlens.ai/more-in-this-section-4/pattern-from-nextjs.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
