Not sure if Managed Warehouse is right for you?See Choose Your Data Path for a side-by-side comparison with connecting your own warehouse.
What you get
When you provision the Managed Warehouse, GrowthBook automatically sets up your data source with everything pre-configured:Tables
We create 3 tables in a ClickHouse database managed by GrowthBook:Fact Table
An Events fact table is pre-built on top of theevents table. This is the base you use to define metrics. It includes 16+ standard columns (timestamp, event name, device ID, geo and browser data, etc.) plus an attributes JSON column with everything your events send, and is ready to use immediately.
Starter metrics
Three metrics are auto-created to get you started:
You can edit these or create your own. Read more about metrics and fact tables.
Default identifiers and dimensions
Identifiers are the columns used to split traffic in experiments, and dimensions let you slice and dice results. These are set up out of the box:- Identifiers:
user_id,device_id - Dimensions:
geo_country,ua_browser,ua_os,ua_device_type,utm_source,utm_medium,utm_campaign
Getting started
1. Provision the Managed Warehouse
Go to Metrics and Data → Data Sources and click Create on the Managed Warehouse option. GrowthBook provisions your ClickHouse database, tables, fact table, and starter metrics in seconds.2. Install the SDK with tracking
Add the GrowthBook SDK to your application with the tracking plugin enabled. Here are the two most common setups:Using eu-west-1?Events default to the
us-east-1 ingestor. If you selected eu-west-1 as your Data Region, add the ingestorHost (or data-event-ingestor-host for the script tag) override — see Sending events to the right region below — otherwise your events won’t reach your warehouse.3. Verify events are flowing
Open the SQL Explorer in GrowthBook and run a quick query to confirm events are arriving:4. Create your first metric
Your auto-created metrics (Page Views per User, Sessions per User, Pages per Session) are ready to use immediately. To create a custom metric:- Go to Metrics and Data → Fact Tables.
- Open the Events fact table.
- Click Add Metric and configure it (for example, a Proportion metric filtered to
event_name = 'Purchase'to track purchase conversion rate).
5. Run your first experiment
With events flowing and metrics defined, you’re ready to experiment:- Create a feature flag in Features.
- Add an Experiment rule to it.
- Start the experiment and watch results flow in on the Results tab.
Benefits
- Fully managed: No infrastructure management, scaling, or maintenance.
- Seamless integration: One-click setup + built-in tracking in our SDKs.
- Instant data: Events are enriched and available within seconds.
- Raw SQL access: Use the SQL Explorer to run custom queries against your data.
How it works
We use ClickHouse, a database optimized for real-time analytics, to store your event data. The process is:- You send analytics events to our scalable ingestion API.
- We enrich and store them in ClickHouse within seconds.
- You can query the data with SQL, define metrics, and analyze experiment results with our stats engine.
Sending events
There are 2 ways to send events to GrowthBook Cloud’s Managed Warehouse:- With our SDKs (limited language support).
- With our Ingestion API.
With SDKs
The following SDKs have a built-in plugin to automatically send events.- HTML Script Tag
- Client-Side JavaScript / React
- Node.js
- Python
- Java
- PHP
- Golang
- Flutter
- Swift (Coming Soon)
- Kotlin (Coming Soon)
HTML Script Tag
Adddata-tracking="growthbook" to your script tag to enable.
window.gbEvents global variable. You can push events to this array, and they will be tracked.
Client-Side JavaScript / React
Use thegrowthbookTrackingPlugin to enable tracking. We recommend also using the autoAttributesPlugin to include many common attributes in your events (browser, session_id, etc.).
logEvent method to track additional custom events:
Node.js
Use thegrowthbookTrackingPlugin to enable tracking:
logEvent method to track additional custom events:
logEvent method that doesn’t require the user context:
Sending events to the right region
The tracking plugin sends events tohttps://us-east-1.gb-ingest.com by default. If you selected eu-west-1 as your Data Region when creating your Managed Warehouse, override the ingestor host so events reach the right ClickHouse cluster instead of being dropped:
- HTML Script Tag: add
data-event-ingestor-host="https://eu-west-1.gb-ingest.com"to the script tag. - JavaScript / React / Node.js: pass
ingestorHosttogrowthbookTrackingPlugin():
Ingestion API
You can also send events directly to our ingestion API. The host depends on the Data Region you chose when creating your Managed Warehouse datasource:us-east-1→https://us-east-1.gb-ingest.comeu-west-1→https://eu-west-1.gb-ingest.com
- event_name: The name of the event (e.g., “Purchase”, “Button Click”)
- properties: Optional key-value pairs with properties of the event itself
- attributes: Optional key-value pairs with attributes of the user or context at the time of the event
- timestamp: Optional ISO timestamp of when the event occurred. Only used when batching events with a
sentAtfield (see Event timestamps below).
Identifiers
To tie events to users for experiment analysis, include identifier keys inattributes:
user_id: a logged-in user ID. Promoted to the top-leveluser_idcolumn at ingest.device_id: an anonymous device or browser ID. Promoted to the top-leveldevice_idcolumn at ingest.anonymous_idorid: also resolve to thedevice_ididentifier, but at analysis time instead of ingest — they stay inside theattributesJSON.
user_id and device_id keys, and use each key for one kind of ID consistently. For example, if you send a logged-in user ID as id today and later start sending a real device ID as device_id, the device_id identifier will mix the two ID spaces and experiment analysis will silently drop units. See Identifiers for how these keys map to identifiers.
Event timestamps
By default, events are timestamped with the time they are received by the ingestion API. If you batch events before sending, you can preserve each event’s original timing by adding a per-eventtimestamp along with a top-level sentAt field:
- sentAt: ISO timestamp of when the request was sent, from the same clock used for the event timestamps
- timestamp: ISO timestamp of when the event occurred. Must be earlier than
sentAt, otherwise it is ignored.
sentAt and each event’s timestamp from our own server time when the request is received. This preserves the relative timing of your events while correcting for client clock skew.
Experiment view events
In order to use GrowthBook’s experiment analysis features, you must send an event every time a user views an experiment. It must match the following format:- event_name: Must be
"Experiment Viewed" - properties: Must include the following key/value pairs:
experimentId: The ID of the experiment being viewedvariationId: The ID of the variation that was shown to the user
attributes with the user attributes that were used to evaluate the experiment, plus any attributes you want to use as dimensions for slicing and dicing. At minimum this must include the attribute the experiment hashes on (its Assign Variation by Attribute), since that’s the identifier used to join exposures to your metrics.
Feature usage events
To take advantage of GrowthBook’s feature usage analytics, you must send an event every time a feature is evaluated with a specific format.- event_name: Must be
"Feature Evaluated" - properties: Must include the following key/value pairs:
feature: The name of the feature being evaluatedvalue: The feature’s value that was returned from the evaluationsource: (optional) The source of the feature value (e.g., “defaultValue”, “experiment”, “force”)ruleId: (optional) The ID of the specific rule that was used to evaluate the feature (or$defaultif the default value was used)variationId: (optional) If the value came from an experiment, the ID of the variation that was returned
Attributes
Attributes are key-value pairs that provide context about the user or environment at the time of the event. They can be used to slice and dice your data in analysis. It’s recommended to include the same attributes you use in your GrowthBook SDK. Some attributes are automatically enriched by the ingestion API:ip: a geoip lookup is done and the following attributes are added. If an ip attribute is not provided, we use the IP address of the request.geo_countrygeo_citygeo_latgeo_lon
ua: the user agent is parsed and the following attributes are added. If a user agent attribute is not provided, we use the user agent of the request.ua_browser(e.g. Safari)ua_os(e.g. macOS)ua_device_type(e.g. mobile)
url: the URL is parsed and the following attributes are added:url_path(e.g. /products/123)url_host(e.g. www.example.com)url_query(e.g. ?utm_source=google)url_fragment(e.g. #section1)
sdk_language(e.g. python)sdk_version(e.g. 1.2.3)
Limits
When calling the ingestion API directly, be aware of the following default limits:- Maximum of 100 events per request.
- Maximum of 1 request per second.
Identifiers and custom attributes
All attributes sent with your events are stored in a native ClickHouse JSON column calledattributes on the events table (event properties live in a properties JSON column). Every attribute is automatically queryable — no setup required.
Identifiers — the attributes used to split traffic in experiments — come in two flavors:
Built-in identifiers
Every table hasuser_id and device_id columns. The columns always exist, but they only carry values when your events include one of the following attribute keys:
The SDK tracking plugin applies this mapping automatically from your SDK attributes, and the Ingestion API does the same for the
user_id and device_id keys. Events that carried their ID as anonymous_id or id are resolved into device_id when queries run, so experiment analysis works with any of these keys — including for past events.
When you assign an experiment by hash attribute, GrowthBook picks the matching identifier automatically: experiments assigned on the id or anonymous_id attribute use the device_id identifier for analysis.
Custom identifiers
Any other scalar attribute marked as an Identifier under SDK Connections → Attributes (for exampleaccount_id) is automatically exposed as a top-level column on your fact tables and available for experiment assignment.
Identifier resolution reads from the
attributes JSON column, so marking an attribute as an identifier applies retroactively to all past events that included it.SQL Explorer
You can use the SQL Explorer to run ad-hoc queries against your events. This is useful for exploring your data, debugging issues, or creating custom reports.The SQL Explorer only allows read-only SELECT queries. Write operations (INSERT, UPDATE, etc.) are prevented from being executed by the platform.
- feature_usage: contains all feature usage events
- experiment_views: contains all experiment view events
- events: contains all other events
SQL best practices
Use indexes
For best performance, take advantage of the indexed columns in each table:- events table:
timestamp: the time the event occurredevent_name: the name of the event (e.g., “Purchase”, “Button Click”)
- feature_usage table:
timestamp: the time the event occurredfeature: the name of the feature being evaluated
- experiment_views table:
timestamp: the time the event occurredexperimentId: the ID of the experiment being viewed
Querying attributes and properties
Theattributes and properties columns are native ClickHouse JSON columns, so you can access fields inside them with dot syntax. Cast the value to get a concrete type:
Identifier columns in custom SQL
The physicaluser_id and device_id columns only contain values that were promoted at ingest — by the SDK tracking plugin, or by the user_id/device_id attribute keys on the Ingestion API. Events that carried their ID as anonymous_id or id keep it inside the attributes JSON instead. GrowthBook-generated queries resolve this automatically, but hand-written SQL reads the raw columns.
If your custom SQL joins or groups on identifiers — especially in a custom fact table used for experiment analysis — use the same resolution expressions GrowthBook uses:
user_id, device_id): experiment analysis joins your fact table to GrowthBook’s exposure queries by identifier, so a fact table that extracts an ID from the JSON under a different name won’t match any exposures.
Large queries
There is a limit of 1000 rows in the SQL Explorer. Returning raw events over a large time period will quickly exceed this limit. To work around this, useGROUP BY in your queries to aggregate results.
One common aggregation is by time intervals. You can use the toStartOf... functions in ClickHouse for this. For example, to get daily event counts:
toStartOfHour, toStartOfMonth, etc. that you can use to group by different time intervals.
FAQ
Can I use the Managed Warehouse alongside my own warehouse?
Yes. You can add a separate data source for your own warehouse at any time and use both simultaneously. Note that each experiment pulls data from a single data source, so you can’t mix metrics from both warehouses within one experiment.How do I add custom identifiers like account_id?
user_id and device_id are built in. To add another identifier, go to SDK Connections → Attributes and mark the attribute as an Identifier. Include it in the attributes of your events and it will be exposed as a top-level column on your fact tables.
Why are the user_id/device_id columns empty when I query directly?
Those columns are only filled at ingest when events include the user_id or device_id attribute keys (the SDK tracking plugin does this for you). If your events carried their ID as anonymous_id or id, it lives in the attributes JSON — experiment analysis resolves it into device_id automatically, but your own SQL needs to do the same. See Identifier columns in custom SQL.

