Inspiration
Creators can generate a thumbnail, voiceover, or short in seconds. But the workflow usually stops at export. The file leaves the AI tool as an ordinary image, audio file, or video, and the information about how it was created can be separated from the asset, forgotten, or lost entirely.
That becomes a much bigger problem as AI-generated media moves into professional publishing workflows. Since 2 August 2026, the EU AI Act's Article 50 transparency obligations have applied. Article 50(2) specifically addresses machine-readable marking and detectability of AI-generated or manipulated content. At the same time, C2PA has matured into an open provenance standard with major technology and media companies including Adobe, Microsoft, BBC, Google, and OpenAI participating in its ecosystem.
Three things have now converged: AI media is generated at scale, C2PA has matured into an industry-backed standard, and Article 50 transparency obligations are in effect. A creator-side provenance layer was not viable before this convergence, and is now necessary.
Every time you generate an AI thumbnail, voiceover, or short, Trace stamps it in under a second before publication, so sponsors, platforms, and viewers can independently verify it came from you.
So I built Trace: a deterministic, sub-second workflow that embeds a real cryptographically signed C2PA provenance record directly into the asset.
Provenance should be a workflow step, not a feature you bolt on after the fact.
What it does
Trace attaches cryptographically-verifiable C2PA provenance manifests to AI-generated assets (images, audio, video) in under one second.
You drop a file into the dashboard, pick which AI model generated it, and Trace:
- Creates a signed C2PA manifest recording the creator attestation, model, prompt, timestamp, and source information
- Signs it with an ES256 key
- Embeds the manifest directly inside the file (not a sidecar)
- Returns a public Provenance Card URL that anyone can verify
Generate → Stamp → Publish → Verify. That's the entire workflow.
The Provenance Card renders the source chain in plain English and has a "Verify cryptographically" button that confirms claimSignature.validated in under 500ms. No account needed: any sponsor, platform, or reviewer can open the URL and see the green "Cryptographic signature: VALID" badge.
Try it: Live demo · Demo video · GitHub
Live C2PA proof: three asset types, independently verifiable:
| Asset | AI Model | Provenance Card |
|---|---|---|
| Image (PNG) | Gemini 3 Pro | View → |
| Audio (MP3) | ElevenLabs v3 | View → |
| Video (MP4) | Sora 2 | View → |
No account needed. Anyone can verify it came from you.
How we built it
The architecture is deliberately simple, with two services, one database, zero agents:
- Backend (Railway): Python 3.12, FastAPI, and
c2pa-python 0.37.10(the official C2PA consortium Python bindings, using the C2PA Rust implementation underneath; Trace emits a C2PA 2.x manifest). SQLite for the compliance dashboard. - Dashboard (Vercel): Next.js 16, TypeScript, Tailwind CSS 4, shadcn/ui, Framer Motion. The browser uploads directly to Railway, avoiding Vercel's 4.5 MB Route Handler limit; the current implementation supports assets up to 100 MB.
- Core path: Zero LLM calls. The C2PA manifest is a deterministic library call; the signature is a deterministic crypto operation. This is intentional: an LLM in the stamping path would add hallucination risk and 200–500ms latency, breaking the sub-second promise.
Under the hood, the Stamper builds a V2 manifest with a c2pa.actions assertion (digitalSourceType = trainedAlgorithmicMedia) plus three Trace-namespaced assertions: std.trace.creator, std.trace.model, and std.trace.prompt. The manifest is signed with ES256 (ECDSA P-256) and embedded directly in the asset file, not stored as a sidecar. Verification reads the manifest back from the file and confirms claimSignature.validated, timeStamp.validated, and assertion.hashedURI.match.
43 tests. 87% coverage (stamper 98%, verifier 84%, API 90%). Fresh-clone verified: git clone → make setup → make test → trace stamp → all green in under 5 minutes.
Challenges we ran into
1. The body-size limit wall. Vercel's Hobby plan caps Route Handlers at 4.5 MB. A 9 MB video would return HTTP 413. I solved this by having the browser upload directly to the Railway backend, completely bypassing the Vercel function. The NEXT_PUBLIC_TRACE_API_URL env var tells the browser where the backend lives.
2. c2pa-python is a 14.8 MB native Rust binding. It can't run in Vercel's serverless environment (exceeds the build timeout). This is why the backend runs on Railway as a Docker container: the Dockerfile installs the native wheel and runs trace serve on the port Railway assigns.
3. The stdlib trace module conflict. Python's standard library ships a trace module. Installing a package named trace would shadow it and break the CLI. The source directory stays python/trace/ but is importable as tracekit via a package-dir mapping in pyproject.toml. The CLI command is unchanged: trace.
4. Stale browser caches. Vercel caches JS chunks for 1 year (max-age=31536000,immutable). When I fixed the upload path, users' browsers kept serving the old code. The fix: bake NEXT_PUBLIC_TRACE_API_URL into the build via .env.production so the URL is inlined as a string literal, and set the client-side file guard to match the actual Railway backend capacity.
Accomplishments that we're proud of
- Real cryptography, not a mock. Every stamp produces a genuine ES256-signed C2PA manifest with
claimSignature.validated,timeStamp.validated, andassertion.hashedURI.match. The verifier reads the manifest from the file itself, not from a database. - Sub-second. A typical stamp completes in ~0.5 seconds. The end-to-end flow (stamp → manifest → verify) runs in under 3 seconds.
- All three asset types work. Image, audio, and video: each stamped with the correct AI model attribution, all returning VALID.
- Zero LLM calls in the core path. Deterministic by design. No hallucination risk, no external API dependency, no latency penalty.
- $0/month on the current free-tier deployment. Railway free tier + Vercel free tier.
- 43 tests, 87% coverage. Fresh-clone verified: a reviewer can clone, install, test, and stamp in under 5 minutes.
What we learned
1. Provenance ≠ truth. A valid C2PA signature proves the manifest hasn't been tampered with since signing; it does not prove the creator's claims (model used, prompt, identity) are truthful. Trace records what the creator attests; the signature guarantees the integrity of that attestation, not its accuracy. This distinction is the most important thing I learned: provenance is about trust infrastructure, not truth enforcement.
2. Compliance language matters. Saying "EU AI Act compliant" is too strong: a C2PA manifest aligns with transparency workflows but doesn't constitute legal compliance. The correct framing is "aligned with Article 50 transparency workflows."
3. The signed file is the source of truth. The signed asset lives on disk with the manifest embedded in the file. The SQLite record is a convenience for the dashboard. If the DB is down, the stamp still succeeds: the manifest is in the file, not the database.
What's next for Trace: The Provenance-First AI Content Engine
- CA-trusted signing certificate. The demo uses the official c2pa-python test fixtures; production deployment needs CA-issued credentials so signatures can participate in a trusted certificate ecosystem.
- Public verifier URL input. Let anyone paste a Trace card URL to verify any asset, not just ones stamped on this instance.
- Batch API + webhook integrations. Auto-stamp when Midjourney or ElevenLabs delivers a new asset.
- Browser extension. Stamp assets on download from AI generation platforms, before they ever leave the tool.
- Multi-creator team workflow. Team accounts with shared signing keys and per-creator attribution.
Built With
- c2pa
- c2pa-python
- css
- es256
- fastapi
- framer
- motion
- next.js
- python
- railway
- react
- recharts
- shadcn/ui
- sqlite
- tailwind
- typescript
- vercel


Log in or sign up for Devpost to join the conversation.