Rawbbit events flowing through app and date filters into a game-design dashboard in Metabase

How to build a game-design dashboard in Metabase with Rawbbit

Rawbbit can deliver game events to ClickHouse and connect Metabase to that data. Metabase starts empty: it does not come with a prebuilt dashboard already prepared for your game.

This article shows how to turn that empty Metabase instance into a small dashboard for game designers and live-ops. We will create charts for game health, the path into a level, difficult levels, and experiments.

The screenshots are examples made with synthetic match-3 data. They show what these charts can look like. They are not a dashboard included with Rawbbit, and the numbers are not results from a customer.

You can build the charts yourself, ask an AI agent to prepare the SQL, or ask us to help define the metrics and design and build the dashboard for your game. That help is a separately scoped service, not an automatically included deliverable.

Before creating a chart

This guide assumes:

  • Rawbbit is already receiving events from your game
  • those events are available in the ClickHouse table analytics.events
  • Metabase is connected to ClickHouse

If the events are not arriving yet, start with How Rawbbit works. Metabase cannot create a metric from an event that was never collected.

You also need to know the app_id used by your game. Every query below contains:

WHERE app_id = 'your.game'

Replace your.game with the real value for your game.

Create the dashboard

In Metabase, create a dashboard and give it a practical name such as Game health or Live-ops overview.

Start from the collection where your team keeps analytics work. Select New in the top-right corner, then choose Dashboard.

Metabase New menu showing Question, SQL query, and Dashboard choices
Creating a question, SQL query, or dashboard from an empty collection.

Enter a name, add a short description if it helps your team, choose the collection, and select Create. Creating the dashboard does not create any metrics yet. It gives you a place to add saved questions.

Metabase dashboard form with name, description, collection, and Create button
Naming and describing a dashboard and choosing its collection.

Do not try to build every possible metric at once. A useful first version needs only a few trusted answers:

  • How many players and sessions do we have?
  • How many levels are started, completed, and failed?
  • Where do players stop before completing a level?
  • Which levels have unusual failure or retry rates?

Economy and experiment charts can come later, when you know those events and parameters are present.

Check which events are available

Before writing a metric, check what the game actually sends.

For a simple no-SQL check:

  1. Select New → Question.
  2. Choose the analytics.events table.
  3. Filter by your app_id and a recent date range.
  4. Summarize by Count of rows.
  5. Group by Event Name.
  6. Show the result as a table and save it.

The filter section should now show the game, environment, and date range. Under Summarize, use Count and group by Event Name.

Metabase question builder filtering synthetic events by app, environment, and date, grouped by event name
Filtering synthetic Rawbbit events and grouping Count by Event Name.

Select Visualize to run the question. The result should be a list of event names and their counts. Keep it as a table, or choose another visualization from the picker at the lower left.

Metabase filtered event results beside the table, bar, line, and other visualization choices
Inspecting filtered synthetic results and choosing a visualization.

The exact labels can differ slightly between Metabase versions.

You can also use a SQL question:

SELECT
  event_name,
  count() AS events
FROM analytics.events
WHERE app_id = 'your.game'
  AND event_date >= today() - 30
GROUP BY event_name
ORDER BY events DESC
LIMIT 50

The SQL editor keeps the query above the result table. Run the query, inspect the first rows, then use Save if the output is correct.

Metabase SQL editor running an event-name count with synthetic results and a Rawbbit ClickHouse database label
Running a synthetic event-name count against the reader-facing Rawbbit ClickHouse database.

If you expect level_failed but it is not in this list, stop here and check the tracking implementation. Renaming a chart will not repair a missing event.

The repeated Metabase workflow

The chart examples below use the same workflow:

  1. Select New → SQL query.
  2. Choose the ClickHouse database connected to Rawbbit.
  3. Paste the query and replace your.game.
  4. Run it and inspect the rows before choosing a visualization.
  5. Select a table, line, bar, or funnel visualization.
  6. Save the question.
  7. Add the saved question to your dashboard.

The screenshots use Rawbbit ClickHouse as the reader-facing database label; the deployed label in a studio's Metabase may differ.

To arrange the finished cards, open the dashboard and select Edit dashboard. The toolbar at the top lets you add saved questions, headings or text, links, sections, and dashboard-level filters. Drag cards to change their order and size, then select Save.

Metabase dashboard edit view with Add questions control and editing toolbar
Edit mode with the Add questions control.

If the result is empty, first check the app_id, date range, event names, and JSON parameter names. An empty result is usually a data mismatch, not a visualization problem.

The chart screenshots below are also synthetic examples. They may show expanded versions of the baseline queries: the baseline SQL does not itself produce the funnel percentage series, the difficult-level completion and duration columns, or the experiment failure, purchase, and revenue columns visible in some screenshots. Treat those extra fields as illustrative and add them only after verifying the event schema and metric definition for your game.

Chart 1: a small game-health summary

Start with one row for the last 30 days: active players, sessions, level starts, completions, and failures.

Synthetic game-health KPI table with players, sessions, level starts, completions, and failures
Synthetic game-health summary; optional purchase and revenue fields are not implied by the SQL.
SELECT
  uniqExact(user_pseudo_id) AS active_players,
  uniqExactIf(session_id, session_id IS NOT NULL) AS sessions,
  countIf(event_name = 'level_started') AS level_starts,
  countIf(event_name = 'level_completed') AS level_completions,
  countIf(event_name = 'level_failed') AS level_failures,
  round(
    100 * countIf(event_name = 'level_completed')
    / nullIf(countIf(event_name = 'level_started'), 0),
    2
  ) AS completion_pct
FROM analytics.events
WHERE app_id = 'your.game'
  AND event_date >= today() - 30

Display this as a table. It is a quick health check, not a finance report and not a retention calculation.

The completion percentage here is completions divided by starts during the selected period. It is useful for monitoring, but it does not follow a player cohort over time.

Purchases and revenue can be added only if the game sends a purchase event and a consistent price parameter. If payment data lives in another database, it must be joined before it can appear reliably in this card.

Chart 2: the path from opening the game to completing a level

A short funnel helps separate an onboarding problem from a level-difficulty problem.

Synthetic four-stage funnel from app opened through session and level started to level completed
Synthetic app-to-level period funnel.
SELECT
  step,
  step_order,
  users
FROM
(
  SELECT 'App opened' AS step, 1 AS step_order,
    uniqExactIf(user_pseudo_id, event_name = 'app_opened') AS users
  FROM analytics.events
  WHERE app_id = 'your.game' AND event_date >= today() - 30

  UNION ALL

  SELECT 'Session started', 2,
    uniqExactIf(user_pseudo_id, event_name = 'session_started')
  FROM analytics.events
  WHERE app_id = 'your.game' AND event_date >= today() - 30

  UNION ALL

  SELECT 'Level started', 3,
    uniqExactIf(user_pseudo_id, event_name = 'level_started')
  FROM analytics.events
  WHERE app_id = 'your.game' AND event_date >= today() - 30

  UNION ALL

  SELECT 'Level completed', 4,
    uniqExactIf(user_pseudo_id, event_name = 'level_completed')
  FROM analytics.events
  WHERE app_id = 'your.game' AND event_date >= today() - 30
)
ORDER BY step_order

Use step as the category and users as the value. A bar chart works on every Metabase installation; use a funnel visualization if it is available.

This is a simple period funnel: it counts players who generated each event during the last 30 days. It does not prove that every player completed the steps in that exact order. A strict ordered funnel needs session or sequence logic.

If the largest drop is between app open and level start, investigate onboarding and tracking before changing level balance. If players start levels but rarely complete them, level difficulty becomes the stronger question.

Chart 3: levels with high failure or retry rates

For a level-based game, this is usually the most useful designer view.

Synthetic difficult-level table showing level IDs, starts, completions, failures, retries, and failure rate
Synthetic difficult-level table, not a supplied template.

In Rawbbit's base events table, game-specific parameters are stored in event_params_json. In this example the key is level_id:

SELECT
  JSONExtractString(ifNull(event_params_json, '{}'), 'level_id') AS level_id,
  countIf(event_name = 'level_started') AS starts,
  countIf(event_name = 'level_completed') AS completions,
  countIf(event_name = 'level_failed') AS failures,
  countIf(event_name = 'level_retried') AS retries,
  round(
    100 * countIf(event_name = 'level_failed')
    / nullIf(countIf(event_name = 'level_started'), 0),
    2
  ) AS failure_rate_pct
FROM analytics.events
WHERE app_id = 'your.game'
  AND event_name IN (
    'level_started',
    'level_completed',
    'level_failed',
    'level_retried'
  )
  AND event_date >= today() - 30
GROUP BY level_id
HAVING level_id != '' AND starts >= 20
ORDER BY failure_rate_pct DESC
LIMIT 50

Display this as a table. The starts >= 20 condition removes rows where the sample is too small to be useful; choose a threshold that fits your traffic.

Do not rank levels by failure percentage alone. A level with 5 starts and 2 failures looks worse than a level with 2,000 starts and 300 failures, but it is much weaker evidence.

The same data can be displayed as a line or bar chart:

Synthetic line chart comparing completion and failure rates across levels
Another synthetic visualization of level performance.

Use level_id on the horizontal axis and rate columns as series. If a level stands out, return to the table and inspect its starts and retries before deciding to rebalance it.

If your game calls the parameter stage_id, mission_id, or something else, replace level_id in the query. Do not guess the key.

Chart 4: results by experiment variant

Build this only if your events contain an experiment identifier or variant.

Synthetic experiment-variant summary comparing players, starts, completions, and completion percentage
Synthetic experiment summary, not a real release decision.
SELECT
  JSONExtractString(
    ifNull(event_params_json, '{}'),
    'experiment_variant'
  ) AS experiment_variant,
  uniqExact(user_pseudo_id) AS players,
  countIf(event_name = 'level_started') AS level_starts,
  countIf(event_name = 'level_completed') AS level_completions,
  round(
    100 * countIf(event_name = 'level_completed')
    / nullIf(countIf(event_name = 'level_started'), 0),
    2
  ) AS completion_pct
FROM analytics.events
WHERE app_id = 'your.game'
  AND event_date >= today() - 30
GROUP BY experiment_variant
HAVING experiment_variant != ''
ORDER BY players DESC

Display this as a table. Always keep the player count beside the result. A variant with a small sample should not drive a release decision.

For a real experiment analysis, also filter by the experiment ID and confirm how players are assigned to variants. Otherwise two experiments using the same variant names can be mixed together.

Ask an agent to prepare the SQL

A game designer does not need to write these queries from memory. An AI agent connected to Rawbbit through MCP can inspect available event names and prepare a query for Metabase.

For example:

Use the ClickHouse table analytics.events. For our game and the last 30 days, prepare a Metabase query that shows level starts, failures, retries, and failure rate by level. First inspect our event names and a sample of event_params_json. Do not invent events or parameter keys. Return the SQL and explain what each row means.

Then:

  1. Paste the query into Metabase.
  2. Run it as a table first.
  3. Compare a few rows with events or a metric you already trust.
  4. Only then choose a visualization and add it to the dashboard.

The agent removes the need to remember SQL syntax. It does not remove the need to verify event names, parameter meanings, and the result.

See How to connect Rawbbit MCP to Codex for the connection setup.

What Metabase cannot repair

Metabase can visualize the data it receives. It cannot repair:

  • events that were never sent
  • event names that change between game versions
  • missing or inconsistent level_id values
  • experiment variants assigned inconsistently
  • purchase data stored elsewhere without a join

When a chart suddenly becomes empty, check the latest event names and parameters before changing the chart.

A reasonable first dashboard

Start with three trusted cards:

  1. game-health summary
  2. app-to-level funnel
  3. difficult-levels table

Add experiment, economy, ads, or progression views after the required events are verified. A small dashboard that answers real questions is more useful than twenty cards nobody trusts.

If your team does not want to build this itself, we can help define the metrics, prepare the SQL, and build the first Metabase dashboards around your game's events as a separately scoped service.