Tell people they’re talking to an AI.
A clear notice, at the latest at the first interaction.
Art. 50(2) marking: 2 Dec 2026 for existing systems.
Three AI Act duties in pictures, the cost of a breach, and a one-click CTO handoff.
A clear notice, at the latest at the first interaction.
Art. 50(2) marking: 2 Dec 2026 for existing systems.
Automatic event records, kept at least six months.
Oversight that lets a person step in or stop.
As amended by Reg. (EU) 2026/1744, the Digital Omnibus.
1Raw documentYour app holds the text, as it does today.
2Cryptographic sealThe SDK seals it with your key, then discards the raw text.
3Fingerprint in FrankfurtOnly the keyed fingerprint goes to the Spurvik console in Frankfurt (fra1).
No-raw-prompt means no raw personal data is persisted. Fingerprints remain pseudonymised data under GDPR Art. 4(5) while your key exists.
SME: under 250 staff and turnover up to €50M.
A ceiling, not an expected fine; Art. 99(7) weighs the measures you had in place. Log scale.
Our hosts (Vercel, Neon on AWS) have US parents; we claim no CLOUD Act immunity, only that the record holds nothing readable. Public documentation, October 2026.
Add your company name. The message is written in this tab and goes nowhere until you send it.
Wrap the model client you already use: an Art. 50 notice flag, an Art. 12 record per call hashed with your key, and an Art. 14 human gate before risky actions.
npm i spurvik ai @ai-sdk/openai
npm i -D spurvik-mcp-server@1.0.4 && ./node_modules/.bin/spurvik-mcp check . --ci
SPURVIK_API_KEY SPURVIK_SIGNING_SECRET SPURVIK_CONTENT_HASH_SECRET SPURVIK_BASE_URL=https://console.spurvik.com
import OpenAI from "openai"; import { withSpurvik } from "spurvik"; const config = { apiKey: process.env.SPURVIK_API_KEY!, signingSecret: process.env.SPURVIK_SIGNING_SECRET!, contentHash: { mode: "keyed", secret: process.env.SPURVIK_CONTENT_HASH_SECRET! }, baseUrl: process.env.SPURVIK_BASE_URL!, riskTier: "limited_art50", // your own classification article50Disclosure: true, // only when your UI shows the AI notice }; const ai = withSpurvik(new OpenAI(), config); // use ai exactly like the OpenAI client; each call gets a keyed HMAC record const res = await ai.chat.completions.create(req);
import { generateText, wrapLanguageModel } from "ai"; import { openai } from "@ai-sdk/openai"; import { spurvikMiddleware } from "spurvik/ai"; // Any AI SDK provider: OpenAI, Anthropic, Gemini or a local model. const model = wrapLanguageModel({ model: openai("gpt-4o-mini"), middleware: spurvikMiddleware(config), // the same config as in the OpenAI tab }); const { text } = await generateText({ model, prompt: ticketText });
import { SpurvikClient } from "spurvik"; const spurvik = new SpurvikClient(config); // the same config as in the OpenAI tab // Holds until a reviewer decides in the hosted queue (Pro and higher). // Throws if the reviewer rejects it or nobody decides in time (120 s by default). await spurvik.requireHumanApproval("bank.pay", { invoiceId: "4471" }); await bank.pay(invoice); // runs only after approval
What your model provider sees, and the keyed fingerprint Spurvik gets instead. Computed in this tab with a public demo key. Nothing is sent.
Your provider, your DPA. Spurvik never receives this text.
inputHashDemo key spurvik-public-demo-key-2026. Use your own SPURVIK_CONTENT_HASH_SECRET (16+ characters) in production. Model call stubbed: the output digest covers an empty string.
SPURVIK_CONTENT_HASH_SECRET (16+ characters, server side).requireHumanApproval(actionName, payload) holds an action until a reviewer decides in the hosted queue (Pro and higher).| Provision | Spurvik control | Status |
|---|---|---|
| Art. 50(1) | AI notice in 24 EU languages (AIDisclosureLabel, badge.js) | spurvik 1.0.8 |
| Art. 50(2) | Marking hooks and a contentMarkingApplied flag on each record; the marking itself comes from your own tool | spurvik 1.0.8Marking: your tool |
| Art. 12, 19(1), 26(6) | One keyed-HMAC record per call, hash-chained | spurvik 1.0.8Hosted in Frankfurt |
| Art. 14 | requireHumanApproval(); the queue records the decision, who made it, when, and the reason given | spurvik 1.0.8Hosted queue: Pro and higher |
| Art. 11, Annex IV | DPO engineering summary download to support your technical documentation | Pro and Team |
| GDPR Art. 5(1)(c), 25, 32 | Redaction, digests only, your key | By design |
List prices, excl. VAT, B2B only.
€0
10,000 events/mo, 30-day log retention. AI notice badge with the “Art. 50 · Spurvik” link.
Create a free account€19/mo
or €190/yr (2 months free). 250,000 events/mo, 90-day log retention in Frankfurt, hosted approval queue, DPO engineering summary, white-label AI notice badge.
Start with Pro€199
One-off. We install your 24-language AI notice, configure Frankfurt call logs and approval gates, and deliver your DPO PDF in 24h. Includes 1 year of Pro (€190 value).
Book the 24h setup€79/mo
or €790/yr (2 months free). Everything in Pro, 2,000,000 events/mo, 12-month log retention.
Start with TeamStripe, our merchant of record (shown at checkout as Link), adds VAT where it applies.
Book a 45-minute walkthroughTreat it as pseudonymised data. Without your key nobody can link it to a person; with it and the original, you can prove a match.
You do, in your environment or KMS. It never travels with events.
No. In the default keyed mode, prompts go only to your model provider. Spurvik receives keyed fingerprints of the prompt and the output, not the text, so 0 bytes of prompt text are stored.
No tool can. Spurvik supplies measures and evidence that support Art. 50, 12 and 14; classification, your DPIA and any conformity assessment stay with you.