Google Firestore
Datafly Signal writes first-party events as documents into a Firestore collection — flexible, scalable NoSQL with real-time sync and offline support.
Why route Google Firestore through Datafly Signal
- The data lands in infrastructure you own. Signal writes to your Google Firestore directly from your own deployment. Datafly operates no intermediary and never holds a copy of your event data.
- Personal data is hashed on the way in. Email, phone (shaped to E.164 first), first, last and full name and postcode are normalised (trimmed and lower-cased) and hashed with SHA-256 inside your own deployment, so the collection holds
email_sha256,phone_sha256and the other digests rather than the raw values. Storing a raw value is a deliberate edit to the installed blueprint. - Only what the blueprint maps is stored. The properties Signal writes are exactly the fields the blueprint maps. Identify traits and client properties the blueprint does not map are never written, so a stray email in an event property cannot land in Firestore in plain text.
- Presets for Retail, Insurance, Travel, Media & Streaming, B2B / SaaS, Automotive and General. Each vertical preset names one field per property in the matching event spec, with canonical names (
transaction_id,value,items), legacy aliases (order_id,revenue,products) read automatically, numbers typed as numbers and currency codes upper-cased. - Client IP and user agent are recorded as event context. Both come from the original visitor request rather than from your server, so geography and device analysis done in the warehouse reflects the actual visitor.
- One consent decision governs every destination. Google Firestore is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
Prerequisites
Before configuring Google Firestore in Signal, you need a GCP project with a Firestore database, a target collection, and a service account.
Create a GCP Account and Project
- Sign up at cloud.google.com if you don’t already have an account.
- Create a new project or select an existing one in the GCP Console.
- Note the Project ID.
Create a Firestore Database
- Go to the Firestore console.
- If prompted, click Create database.
- Choose the Firestore mode:
- Native mode — recommended for Signal. Provides real-time listeners, offline support, and document-based queries.
- Datastore mode — optimised for server-side workloads, no real-time features.
- Select a Location close to your Signal deployment.
- Click Create database.
The Firestore mode cannot be changed after creation. Choose Native mode for the most flexibility.
Define a Collection
Firestore collections are created automatically when the first document is written. However, you can optionally create the collection structure in advance:
- In the Firestore console, click Start collection.
- Enter the Collection ID (e.g.
events). - Add a sample document or click Auto-ID and Save (you can delete this placeholder later).
Signal will create documents in the specified collection automatically. Each event becomes a separate document with the message_id as the document ID.
Create a Service Account
- Go to IAM & Admin > Service Accounts > Create Service Account.
- Enter a name (e.g.
datafly-signal-firestore). - Grant the Cloud Datastore User role (
roles/datastore.user) — this role covers both Firestore Native and Datastore mode. - Click Done.
Generate a Service Account Key
- Click on the service account.
- Go to Keys > Add Key > Create new key > JSON.
- The key file will download. Store it securely.
Store the JSON key file securely. Do not commit it to version control.
Configuration
| Field | Type | Required | Description |
|---|---|---|---|
project_id | string | Yes | The Google Cloud project ID that contains the Firestore database. |
collection | string | Yes | The Firestore collection name to write documents to. |
service_account_json | secret | Yes | The full JSON key file content for a GCP service account with Firestore permissions. |
Signal Setup
Quick Setup
- Navigate to Integrations in the sidebar.
- Open the Integration Library tab.
- Find Google Firestore or filter by Database.
- Click Install, select a variant if available, and fill in the required fields.
- Click Install Integration to create the integration with a ready-to-use default blueprint.
API Setup
curl -X POST http://localhost:8084/v1/admin/integration-catalog/google_firestore/install \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Google Firestore",
"variant": "default",
"config": {
"project_id": "datafly-analytics",
"collection": "events",
"service_account_json": "{\"type\": \"service_account\", ...}"
},
"delivery_mode": "server_side"
}'Schema
Each event becomes one document in the collection, with the message_id as the document ID (a redelivered event overwrites its own document):
| Field | Contents |
|---|---|
event_type | track, page, identify, and so on. |
event_name | Signal event name (snake_case), for example purchase. |
anonymous_id, user_id | Visitor identifiers (user_id empty when not known). |
timestamp, received_at | Client event time and receive time (Firestore timestamps). |
org_id, pipeline_id | Signal identifiers. |
properties | A map of the fields the blueprint mapped (below). |
context | The event context: page, device, campaign, consent, IP and user agent. |
collected_ids, click_ids | Identifier maps collected with the event. |
Firestore documents cannot exceed 1 MiB. Google limits a collection with an indexed, steadily increasing field such as timestamp to 500 writes per second; above that, add a single-field index exemption for timestamp and received_at. Field names with special characters, such as @root, must be quoted with backticks in field paths (properties.`@root`.email_sha256).
What the properties hold
The blueprint decides what properties contains, and only mapped fields are written (identify traits and unmapped client properties never are):
- The event’s own fields from the preset sit at the top level, for example
transaction_id,value,currency,items,insurance_typeorpolicy_term_months. - The preset’s global block sits under
@root: copies of the envelope (event_name,event_type,user_id,anonymous_id,event_id,message_id,event_timestamp,page_url,page_referrer,ip_address,user_agent,locale,timezone,source_id),utm_source,utm_medium,utm_campaign, the consent flagsconsent_analyticsandconsent_marketing, and the hashed identityemail_sha256,phone_sha256,first_name_sha256,last_name_sha256,name_sha256. identifyaddsname_sha256andpostal_code_sha256at the top level.- An event the preset does not list stores its envelope and the
@rootblock only.
Mapped fields stay inside properties; they are not lifted to top-level fields. What else a row carries outside the blueprint (the whole event context) is under review in #1414.
Stored event context
Alongside the fields your blueprint maps (where email, phone, names and address are stored as normalised SHA-256 by default), each document carries the event’s collected context exactly as Signal received it. The blueprint does not filter or hash the context: this is deliberate (decision 2026-09-23), so the context is complete for attribution, fraud and debugging queries, and it is listed here so you can decide what to keep.
| Stored | What it contains |
|---|---|
| Visitor request | IP address, user agent, Accept-Language, locale and timezone |
| Page | URL including its query string, path, title and referrer |
| Campaign | UTM source, medium, campaign, term and content |
| Consent | The visitor’s consent state |
| Location | GeoIP country, region and city, and the network (ASN) |
| Device | Screen size; for app events the OS and version, manufacturer, model, advertising ID and IDFV when the app collected them |
| Vendor IDs | Cookie and click identifiers in vendor_ids (for example the _fbp browser ID, gclid, ttclid, the GA client ID) |
| Session and library | Session ID, number and engagement time; the collector’s name and version |
| Partner attributes | Profile attributes from partner enrichment (partner_attrs) |
They are stored as the document’s context field (Bigtable: the context column), using the event context’s JSON field names, beside anonymous_id and user_id. Click and collected IDs outside the context are stored only where the blueprint maps them.
The IP address, device and advertising IDs, and cookie and click identifiers are personal data under UK and EU GDPR. To keep any of them out of storage, strip, mask or hash the field for every integration with the organisation data layer, apply URL redaction to page URLs, or remove it in the installed blueprint; and set the storage’s retention to match your privacy notice. See Personal data by integration.
Consent
Firestore is a first-party destination under your control, gated by the same consent state as every other destination. Each stored event also records the visitor’s consent at collection time: the preset writes consent_analytics and consent_marketing under @root in the properties (properties.`@root`), and the full consent object is in the context. Use them in views or queries if your governance needs a per-row consent filter.
Testing
- Enable the integration in Signal and trigger a test event on your website.
- Open the Firestore console and navigate to the
eventscollection. - Verify that event documents are appearing with the correct fields and data.
- Click on individual documents to inspect the full event payload.
- In Signal, check the Live Events view to confirm delivery status shows as successful.
Troubleshooting
| Problem | Solution |
|---|---|
| Events not appearing in Firestore | Verify the project ID, collection name, and service account JSON are correct. |
Permission denied (403) | The service account lacks the Cloud Datastore User role. Add it in IAM & Admin > IAM. |
NOT_FOUND | The Firestore database has not been created in this project. Create it in the Firestore console. |
| Invalid service account JSON | Ensure you pasted the complete JSON key file content. |
RESOURCE_EXHAUSTED | You have exceeded Firestore write quotas. Check the quotas page and consider batching. |
| Wrong Firestore mode | If the database is in Datastore mode, the collection structure differs. Verify the mode in the Firestore console. |
| Document size limit | Individual Firestore documents cannot exceed 1 MB. Check the event payload size. |
Visit Google Firestore documentation for full API reference, security rules, and query best practices.