Self-host / Embed
glassprint-server container (Docker / Helm / Terraform) is the alternative. Either way, your fraud signals never leave your perimeter. A managed SaaS is design-partner onboarding, not open self-signup.Option A — Embed the engine in your backend (primary)
The engine libraries are embeddable, self-contained ports of glassprint-server. Add one dependency and your backend automatically serves the full glassprint product in-process — every HTTP endpoint, storage, and the full processing pipeline — with no separate server to deploy or operate.
Node — Express middleware
npm i @noidme/glassprint-engine express
import express from 'express';
import { createEngine } from '@noidme/glassprint-engine';
import { glassprintEngine } from '@noidme/glassprint-engine/express';
const engine = await createEngine({
storage: { driver: 'postgres', url: process.env.DATABASE_URL }, // or 'sqlite' for single-instance
kids: ['acme'],
masterSecret: process.env.GLASSPRINT_MASTER_SECRET,
});
express().use(glassprintEngine(engine)).listen(8080);
// Auto-mounted: GET /_fp/pubkey POST /_fp/i/v1 POST /me POST /privacy/* GET /healthzNode — Fastify plugin
import Fastify from 'fastify';
import { createEngine } from '@noidme/glassprint-engine';
import { glassprintFastify } from '@noidme/glassprint-engine/fastify';
const engine = await createEngine({
storage: { driver: 'postgres', url: process.env.DATABASE_URL },
kids: ['acme'],
masterSecret: process.env.GLASSPRINT_MASTER_SECRET,
});
const app = Fastify();
app.register(glassprintFastify, { engine });
await app.listen({ port: 8080 });Go — net/http handler
go get github.com/noidme/glassprint-engine-go
import (
glassprint "github.com/noidme/glassprint-engine-go"
"net/http"
"log"
"os"
)
eng, err := glassprint.New(glassprint.Config{
MasterSecret: os.Getenv("GLASSPRINT_MASTER_SECRET"),
Kids: []string{"acme"},
// Storage: store, // nil = in-memory (dev); use SQLite or Postgres adapter in production
})
if err != nil { log.Fatal(err) }
// Mount at root, or under a prefix:
// mux.Handle("/gp/", http.StripPrefix("/gp", eng.Handler()))
http.Handle("/", eng.Handler())
log.Fatal(http.ListenAndServe(":8080", nil))Python — FastAPI (ASGI)
pip install "glassprint-engine[fastapi]"
from fastapi import FastAPI
import glassprint_engine as gp
engine = gp.create(
storage="postgresql://user:pass@localhost/glassprint", # or "sqlite:///glassprint.db"
kids=["acme"],
master_secret=os.environ["GLASSPRINT_MASTER_SECRET"],
)
app = FastAPI()
app.include_router(gp.asgi.router(engine)) # all endpoints auto-mounted
# uvicorn main:appJava — Spring Boot starter (zero-wiring)
Add the starter dependency and set two properties. Spring Boot auto-configuration registers every bean and controller — no manual wiring required.
<dependency> <groupId>com.noidme</groupId> <artifactId>glassprint-engine-spring-boot-starter</artifactId> <version>0.1.0</version> </dependency>
glassprint.master-secret=your-at-least-32-char-production-secret glassprint.kids=acme # optional: glassprint.jdbc-url=jdbc:postgresql://localhost/glassprint
The Java engine also ships a framework-agnostic core (glassprint-engine) for Javalin, Vert.x, Micronaut, or plain HttpServer — mount individual endpoint handlers directly.
Storage options (all engines)
| Driver | When to use it |
|---|---|
| In-memory | Dev and tests only — not durable, lost on restart. |
| SQLite (Node: node:sqlite; Python: stdlib; Go/Java: stdlib sql) | Single-instance durable deployments. Zero extra dependencies for the engine itself. |
| Postgres | Multi-instance (horizontal scale). Nonce claims are atomic via INSERT ... ON CONFLICT; ledger appends serialized with an advisory lock. |
Keys and auth (embed)
All engines derive keys the same way as glassprint-server: one master secret (supply from your secret manager) via HKDF-SHA256 derives per-customer seal keys, per-(kid, epoch) visitorId HMAC keys, the ledger key, and the transparency key. Supply masterSecret from a secret manager for multi-instance deployments (or the engine auto-generates and persists one for single-instance dev). The privacy-rights API is fail-closed by default — use createOidcAuthenticator() (Node/Go) or the OIDC JWT authenticator (Python/Java) in production; the dev header authenticator is off unless explicitly opted in.
Option B — Standalone glassprint-server (Docker / Helm / Terraform)
The standalone server is a dependency-light Node 24 container — the same identification engine, run as a separate service. Use this option when your primary backend is not in a supported engine language, or when your team prefers to operate it as a separate tier.
The container
The server is stateless and scales horizontally — all durable state lives in Postgres and Redis. The same image runs everywhere; only the connection strings change.
# bring up Postgres + Redis, then the server
docker compose --profile server up
# server binds 127.0.0.1:8080 (GLASSPRINT_PORT to override)
curl localhost:8080/healthz # → {"ok":true}Backends
Backends are selected from the environment: Postgres + Redis when configured (GLASSPRINT_PG_URL / GLASSPRINT_REDIS_URL), in-memory otherwise (dev / single-instance only). The Postgres schema is standard 14+ and idempotent; Redis provides the atomic replay nonce and the cross-replica rate limiter. The ledger appends are advisory-lock-serialized so replicas stay consistent.
Deploy — Docker, Helm, Terraform
The repo ships infrastructure for all three, cloud-portable by construction:
- Docker — the
Dockerfile+docker-compose.ymlfor local and single-node. - Helm —
deploy/helm/glassprint(chart, deployment, values), including theexternalTrafficPolicy: Localguidance the JA4 trust boundary needs behind a load balancer. - Terraform — a
deploy/terraform/gcpskeleton.
The same image runs on GCP (Cloud Run + Cloud SQL + Memorystore, or GKE), Azure (Container Apps / AKS + Flexible Server + Azure Cache), or AWS (ECS/Fargate or EKS + RDS + ElastiCache) with no code change — secrets come from each cloud's secret manager.
The JA4 edge options
The JA4 / HTTP2 / TCP network tier is captured at your edge and forwarded over the CIDR trust boundary. It is vendor-neutral — pick the one that fits your stack, or skip it entirely and let the anti-spoof confidence cap take over:
| Option | When to use it |
|---|---|
| Cloudflare Worker | You already front your traffic with Cloudflare — drop in the worker and forward the authentic JA4 header. |
| CloudFront | AWS-native edge; use CloudFront's native JA4 fingerprint. |
| Go JA4 proxy | Self-host the reverse proxy: it terminates TLS, computes JA4 per the FoxIO spec, strips client-spoofed x-glassprint-* headers, and forwards the authentic one. |
| None | Skip JA4 — the server marks topology untrusted-direct and the anti-spoof confidence simply caps. Everything else still works. |
GLASSPRINT_EDGE_RANGES / _CF_RANGES / _CLOUDFRONT_RANGES). It never derives the client IP from X-Forwarded-For, and an untrusted peer has its headers stripped. (The same CIDR trust boundary applies to the embedded engines via their trust / Trust config field.)Keys and auth (standalone server)
One root secret (GLASSPRINT_MASTER_SECRET, a KMS-random key) derives, via HKDF-SHA256, the per-customer seal keys, the per-(kid, purpose, epoch) visitorId HMAC keys, the ledger key, and the transparency key. The privacy-rights API is fail-closed by default — production verifies a bearer JWT (ES256/RS256; none/HS* rejected); the trivially-spoofable header authenticator is dev-only and off unless explicitly opted in.
Honest limits to plan around
- Identity resolution is exact-match in both options today. The fuzzy trained-ML linker is roadmap, not wired into the live ingest path.
- The cross-browser
deviceIdfield is always null today — it is a placeholder for theprecise-device-identificationroadmap purpose. - The Java engine multi-instance ledger uses a JVM-level lock (correct for single-process use). For multi-replica deployments sharing one DB, use the standalone server which adds a Postgres advisory lock.
- The
/meper-signal view returns 404 — the engine retains no raw per-signal values by design; the rich transparency view is client-driven and roadmap. - The Marketplace packaging (GCP / Azure managed app) is a roadmap target, not built.