The Invoance Audit Viewer Is Now a React Component You Can Embed
The audit log page your enterprise customers keep asking for is now a drop-in React component. @invoance/audit-viewer is the exact package our hosted portal mounts: signed event table, filters, CSV/JSON export, live refresh, and signature verification that runs in your customer's browser. Here is what shipped and how to embed it.
The audit log page is now a component
Enterprise customers do not just ask whether you have an audit log. They ask where it is. And the answer they want is: right there in your product, under Settings.
That page is now something you can install. @invoance/audit-viewer is the viewer that powers our hosted audit portal, published as an npm package. Mount it on your admin page (say, admin.yourapp.com/audit) and each of your customers gets a full audit experience inside your product: the signed event table, filters by actor, action, and date, CSV/JSON export, and live updates as new events arrive.
It renders as a native React component in your DOM: no iframe, no styling conflicts. And because it is literally the same component the hosted portal mounts, whether you hand a security team a one-time link or embed the page natively, your customers see the same thing and the proof works the same way.
npm install @invoance/audit-viewerKey insight. React 18 or newer, no other runtime dependencies. The stylesheet ships compiled and prefixed: no Tailwind required, themed entirely by CSS variables.
What your customers see
The event table shows actor, targets, action, and gap-free sequence numbers, with filters, keyset paging, export, and a quiet 15-second refresh while the page is idle.
The part we care most about is the detail drawer. Click any row and your customer sees the raw signed event next to a Verify signature button. The verdict reads Authentic. Then they can edit any field in the editor, change one character of the payload, and verify again: it flips to Tampered, computed entirely in their browser with the tenant's published public key. Trust that does not depend on taking anyone's word for it, including ours.
The same component also doubles as a stream configuration screen: mint the session with intent log_streams instead of audit_logs and it renders the SIEM webhook destination setup rather than the event table, so "stream your logs to your own security tooling" is a page you can offer without building it either.
One server-side piece: minting the session
The component authenticates with a short-lived, org-scoped portal session that your backend mints for whichever of your customers is signed in. This is the only server-side work.
// app/api/audit-portal-token/route.ts
import { InvoanceClient } from "invoance";
const client = new InvoanceClient({ apiKey: process.env.INVOANCE_API_KEY });
export async function POST() {
const organizationId = await currentCustomerOrgId(); // however your app resolves it
const session = await client.audit.portalSessions.create({
organization_id: organizationId,
intent: "audit_logs",
session_duration_seconds: 3600,
});
return Response.json({ token: session.token });
}Key insight. Your Invoance API key must never reach the browser. Mint server-side and return only the one-time token. It is useless for anything except opening this one organization's viewer.
Mount it
On the client, pass a callback that fetches a fresh token from that endpoint. It is a callback rather than a static prop on purpose: when the session expires, the component re-mints through your endpoint automatically, so expiry never strands the visitor.
"use client";
import { AuditLogViewer } from "@invoance/audit-viewer";
import "@invoance/audit-viewer/styles.css";
export default function AuditPage() {
return (
<AuditLogViewer
getPortalToken={async () => {
const r = await fetch("/api/audit-portal-token", { method: "POST" });
return (await r.json()).token;
}}
/>
);
}Theming and fit
Nine CSS variables (HSL triples, shadcn-style) drive every color in the component. Override them on :root, on any ancestor, or through the theme prop; bare names get the --inv- prefix automatically. A dark embed that matches your product is a handful of lines, so the viewer reads as your page, not a widget from someone else.
<AuditLogViewer
getPortalToken={getPortalToken}
theme={{ variables: { background: "240 6% 12%", foreground: "0 0% 98%", border: "240 6% 20%", muted: "240 5% 16%", popover: "240 6% 12%" } }}
/>The failure modes are handled
The exchanged session is org-scoped: it can only ever read the one organization it was minted for, and your tenant id is never exposed to the visitor. Portal traffic is rate-limited per visitor IP and never counts against your API budget.
On a 401 mid-session the component calls getPortalToken once and retries; if that fails it shows a clear expiry message and calls onSessionExpired. A rate-limited token exchange (many visitors behind one office NAT clicking at once) retries automatically honoring Retry-After, and a one-time link is not consumed by a rate-limit rejection.
In browsers whose Web Crypto implementation lacks Ed25519, the tamper test still checks the event hash and reports the signature as not verifiable in this browser, explicitly distinct from a failed verification, so nobody mistakes a browser limitation for tampering.
Get started
If you already send Invoance events, embedding the viewer is an afternoon of work: install the package, add the token endpoint, mount the component. If you do not yet, the free tier covers 10,000 events a month, and the Clerk and Auth0 integrations will fill a log with zero code while you evaluate. The full guide, covering props, theming variables, and session semantics, lives in the developer docs.
- Embeddable viewer guide— Install, token endpoint, props reference, theming, and failure modes.
- Audit logs quick start— Sending the signed events the viewer displays.
- Source on GitHub— The viewer package, open source under the Invoance org.
Signed, independently verifiable activity logs you can embed, stream, and export, one API call per event.
Recommended
How to Export Audit Logs for Enterprise Customers: Signed, Verifiable, Audit-Ready
Any system can dump audit logs to a CSV. The problem is that a CSV is a file you are asking an auditor to trust. This guide shows how to export audit logs as signed, independently verifiable records: paginated from a real API, with a per-record Ed25519 signature and a gapless sequence that proves nothing was dropped or altered.
Official Invoance SDKs, Now in Eight Languages
The Invoance client libraries now cover eight languages. Every SDK anchors events, documents, and AI outputs to an append-only ledger, signs them with your tenant's Ed25519 key, and verifies signatures entirely client-side — so the proof holds up whether or not anyone trusts Invoance. Here is what shipped and how to start.
Why Traditional Audit Logs Fail Under Regulatory Scrutiny
Your application logs record what happened. But in an audit or legal proceeding, the first question is not what your logs say, it is whether anyone can trust your logs. Traditional logging has a fundamental integrity problem that most teams do not address until it is too late.
Invoance Audit Logs vs WorkOS Audit Logs: An Honest Comparison
Both products record who did what in your customers' accounts, and both ship a portal, streaming, and exports. The fork in the road is what happens after an event is stored: WorkOS asks your customer to trust the record, Invoance signs it so they can check. A feature-by-feature and price-by-price comparison, with sources.