Fingerprint to BigQuery
This server flow turns raw request signals into a privacy-friendly identifier before events reach BigQuery. The Express source extracts the client IP and user agent, the fingerprint transformer hashes them into user.hash, and the GCP destination writes the events to a table. The ingest keys must be ip and userAgent, the fingerprint's default inputs (ingest.ip, ingest.userAgent); the transformer anonymizes the IP, reduces the user agent and keys the hash with a secret salt.
{
"version": 4,
"flows": {
"default": {
"config": {
"platform": "server",
"bundle": {
"packages": {
"@walkeros/collector": { "version": "^4" },
"@walkeros/server-source-express": { "version": "^4" },
"@walkeros/server-transformer-fingerprint": { "version": "^4" },
"@walkeros/server-destination-gcp": { "version": "^4" }
}
}
},
"sources": {
"express": {
"package": "@walkeros/server-source-express",
"next": "fingerprint",
"config": {
"ingest": {
"map": {
"ip": { "key": "ip" },
"userAgent": { "key": "headers.user-agent" }
}
}
}
}
},
"transformers": {
"fingerprint": {
"package": "@walkeros/server-transformer-fingerprint",
"config": {
"settings": { "salt": "$env.FINGERPRINT_SALT", "length": 16 }
}
}
},
"destinations": {
"bigquery": {
"package": "@walkeros/server-destination-gcp",
"import": "destinationBigQuery",
"config": {
"settings": {
"projectId": "my-analytics-project",
"datasetId": "events",
"tableId": "raw_events"
}
}
}
},
"collector": { "run": true }
}
}
}Run it
Save the config as flow.json and run the fingerprint transformer of the built flow on an event. --ingest passes the request context the Express source extracts, the client IP and user agent, and the salt comes from the environment. Nothing is written to BigQuery:
FINGERPRINT_SALT=change-me npx walkeros push flow.json -e '{"name":"page view"}' --simulate transformer.fingerprint \
--ingest '{"ip":"203.0.113.7","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"}'You should see, besides an Output: line naming the built bundle before each Simulating line (your hash differs, as it depends on the salt and the day):
Simulating transformer: fingerprint
success: true
transformer.fingerprint
event {"name":"page view","user":{"hash":"8015a6ca3b754e5e"}}
Duration: 58621msWhat you get
In production every event lands as one row in your table, using the standard walkerOS schema (name, entity, action, timestamp, user, and more). The destination receives an appendRows call, and the user column carries the hash in place of a raw IP or user agent (from the package's examples):
['appendRows', [{
"name": "page view",
"entity": "page",
"action": "view",
"user": "{\"hash\":\"158f99cc06e33fd6\"}",
...
}]]The hash rotates daily by default, so a visitor is not tracked across days. Use a long random salt per deployment in production.
Next steps
- Fingerprint transformer: Salt, rotation, site separation, and extra fields
- GCP destination: BigQuery table setup and mapping