> ## Documentation Index
> Fetch the complete documentation index at: https://www.text.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Build an extensible reports dashboard in Metabase

> Build a Metabase dashboard for Text reports you can fully customize and extend — every chart is editable SQL, backed by your own Postgres database.

This guide is for teams who want Text reports they can customize or connect with their own data. It sets up [Metabase](https://www.metabase.com/), a free, open-source BI tool, backed by a Postgres database you control, so every chart is a SQL query you can edit or extend.

By the end of this guide, you'll have a Metabase dashboard showing your team's reports data, built on a database that's open to build on further.

## Prerequisites

**You'll need:**

* [Docker and Docker Compose v2](https://docs.docker.com/get-started/get-docker/), to run Postgres and Metabase.
* A [Text account](https://accounts.livechat.com/signup?landing_page=https%3A%2F%2Fwww.text.com%2F\&client_id=fc7bf1555adb6d3d2a441f10fd5b6eb5\&redirect_uri=https%3A%2F%2Fwww.text.com%2Fapp\&response_type=token\&source_type=website\&source_id=header-signup\&source_url=https%3A%2F%2Fwww.text.com%2F) with permission to create personal access tokens.
* [Git](https://git-scm.com/downloads), to clone the [example repository](https://github.com/livechat/text-metabase-integration).

<GitHub.Repo repo="livechat/text-metabase-integration" variant="flat" />

This guide sets Metabase up and builds the dashboard for you — you don't need prior Metabase experience to complete it. Familiarity with Metabase (editing questions, adding cards) will help if you want to customize the dashboard afterward.

<Warning>
  Use this setup only on your own machine. It stores credentials in a local
  `.env` file and doesn't configure HTTPS. Don't expose this Metabase instance
  to the internet or a shared network as-is.
</Warning>

## Set up the dashboard

This guide starts a new, local Metabase instance. Three things work together: **Text** provides the report data, **Postgres** stores a local copy of it, and **Metabase** reads that copy and displays the dashboard.

<Steps>
  <Step title="Create a personal access token">
    In Text, go to **Settings → API access → [Personal access tokens](https://www.text.com/app/settings/integrations/api-access/personal-access-tokens)** and create a token with the `reports_read` [scope](/docs/authentication/scopes) — this is the permission that lets the exporter read report data. No write access is required.

    Copy the Base64-encoded token value that Text displays — this is your combined `account_id:personal_access_token`. The exporter uses this directly as your Text API access.

    <Warning>
      Treat this value like an equivalent to your account's API password. Don't commit it or share it outside a secrets manager.
    </Warning>
  </Step>

  <Step title="Clone the repo and configure the environment">
    In your terminal, clone the repository and copy the example environment file:

    ```shell theme={null}
    git clone https://github.com/livechat/text-metabase-integration.git
    cd text-metabase-integration
    cp .env.example .env
    ```

    The `.env` file holds the settings and credentials this local setup needs. Open the file you just created — in any text editor — and set:

    ```shell theme={null}
    # Base64-encoded Account ID and personal access token from step 1
    TEXT_BASIC_AUTH=

    # Local Postgres database name and user — the defaults work fine for this quickstart
    POSTGRES_DB=text_analytics
    POSTGRES_USER=postgres

    # Choose any password — this creates a brand-new local Postgres database, so there's nothing to look up
    POSTGRES_PASSWORD=secret-password

    # Choose an email and password for the local Metabase administrator account — you'll type these same values into Metabase's setup screen in a later step, so they need to match what's here
    METABASE_ADMIN_EMAIL=admin@example.com
    METABASE_ADMIN_PASSWORD=change-me1
    ```

    Due to Metabase's password policy, `METABASE_ADMIN_PASSWORD` must contain at least one digit.
  </Step>

  <Step title="Start Postgres and Metabase">
    In your terminal (still inside `text-metabase-integration`), run:

    ```shell theme={null}
    docker compose up -d
    ```

    This starts Postgres, which stores the exported report data and Metabase's own settings. It also starts Metabase itself — the dashboard, at `http://localhost:3000` — in the background. You can keep using this same terminal for the rest of the steps.
  </Step>

  <Step title="Export report data">
    Run the exporter:

    ```shell theme={null}
    docker compose --profile jobs run --rm exporter
    ```

    This copies the latest 30 days of first response time, CSAT, and chat-duration data from Text into the local Postgres database. When it finishes, the terminal shows `export complete`. You can run this command again any time you want to refresh the dashboard.

    <Accordion title="How the export works">
      This creates the report tables on first run. Then it calls three Reports API v3.6 endpoints for the latest 30 days, measured in UTC, and writes the results to Postgres:

      | Endpoint                           | Populates                                        |
      | ---------------------------------- | ------------------------------------------------ |
      | `POST /reports/agents/performance` | `agent_performance`, `agent_performance_summary` |
      | `POST /reports/chats/ratings`      | `chat_ratings`                                   |
      | `POST /reports/chats/duration`     | `chat_durations`                                 |

      Each call sends the same request shape to `https://api.livechatinc.com/v3.6`, with your Basic-auth credential from step 1:

      ```http theme={null}
      POST /v3.6/reports/chats/ratings HTTP/1.1
      Authorization: Basic <TEXT_BASIC_AUTH>
      Content-Type: application/json

      {
        "distribution": "day",
        "timezone": "UTC",
        "filters": { "from": "2026-07-11T00:00:00Z", "to": "2026-08-10T00:00:00Z" }
      }
      ```

      `agent_performance` and `agent_performance_summary` are fully replaced on every run. They only ever reflect the latest 30-day window, and they hold no history.

      `chat_ratings` and `chat_durations` work differently — they're saved by date and updated if that date already exists, so their history accumulates across runs. That's why the dashboard's "by agent" card only ever shows a current snapshot, while the daily trend cards build up over time.
    </Accordion>
  </Step>

  <Step title="Complete Metabase's first-run setup">
    Metabase already has its own database for storing dashboards and settings. This is separate from `text_analytics`, the database the exporter writes report data into.

    During first-run setup, complete your initial admin configuration. Metabase will also ask whether you want to add a database — choose "I'll add my data later". The next step connects the report data automatically, so adding a database manually here could leave you with a duplicate.

    Open [http://localhost:3000](http://localhost:3000) and step through Metabase's setup screen using the exact `METABASE_ADMIN_EMAIL` and `METABASE_ADMIN_PASSWORD` values from `.env`.

    <Tip>
      If you've used this local instance before and don't see the first-run setup screen, reset it with [stop or reset](#stop-or-reset).
    </Tip>
  </Step>

  <Step title="Bootstrap the dashboard">
    In a terminal, run:

    ```shell theme={null}
    docker compose --profile jobs run --rm dashboard-bootstrap
    ```

    This connects Metabase to the local Postgres database and creates the **Text Service Quality** dashboard with four cards. When it finishes, the terminal shows `dashboard bootstrap complete`.

    <Accordion title="How the dashboard connection works">
      This job signs in with your admin credentials, then:

      1. Finds or creates a **Text Analytics** Postgres connection pointing at the `postgres` container.
      2. Finds or creates the **Text Service Quality** dashboard.
      3. Finds or creates each of four cards on that dashboard, skipping any that already exist — safe to run again after a new export.

      The connection details it fills in:

      | Field         | Value                                         |
      | ------------- | --------------------------------------------- |
      | Host          | `postgres`                                    |
      | Port          | `5432`                                        |
      | Database name | your `POSTGRES_DB` (default `text_analytics`) |
      | Username      | your `POSTGRES_USER` (default `postgres`)     |
      | Password      | your `POSTGRES_PASSWORD`                      |

      Each card is a Metabase question built with SQL, run against the exported tables:

      ```sql theme={null}
      -- Overall first response time
      SELECT first_response_time_seconds AS seconds
      FROM agent_performance_summary
      WHERE id = true
      ```

      ```sql theme={null}
      -- First response time by agent
      SELECT agent_id, first_response_time_seconds AS seconds
      FROM agent_performance
      WHERE first_response_time_seconds IS NOT NULL
      ORDER BY seconds
      ```

      ```sql theme={null}
      -- Daily CSAT percentage
      SELECT report_date AS day, csat_percent
      FROM chat_ratings
      WHERE csat_percent IS NOT NULL
      ORDER BY day
      ```

      ```sql theme={null}
      -- Daily average chat duration
      SELECT report_date AS day, average_duration_seconds AS seconds
      FROM chat_durations
      WHERE average_duration_seconds IS NOT NULL
      ORDER BY day
      ```
    </Accordion>
  </Step>

  <Step title="View the dashboard">
    In Metabase, open **Dashboards → Text Service Quality**.

    You should see overall first response time, first response time by agent, daily CSAT, and daily average chat duration — assuming your account had chat activity in the last 30 days.
  </Step>
</Steps>

## Troubleshooting

| Symptom                            | Likely cause                                                                           | Fix                                                                                                          |
| ---------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Authentication error               | `TEXT_BASIC_AUTH` is incomplete, or the token is missing the `reports_read` scope      | Create a new token with the `reports_read` scope and update `.env`                                           |
| Can't open Metabase                | Docker isn't running, or the containers didn't start successfully                      | Run `docker compose ps` to confirm both containers are running, or `docker compose logs` to check for errors |
| Exporter can't connect to Postgres | Postgres hasn't finished starting, or Docker isn't running                             | Run `docker compose ps` to confirm Postgres and Metabase are running, then try the exporter again            |
| Bootstrap can't sign in            | The email or password entered in Metabase's browser setup doesn't exactly match `.env` | Check both values against `.env`                                                                             |
| Dashboard is empty                 | No chat activity in the last 30 days on the connected Text account                     | Confirm there's recent chat activity, or use an account that has some                                        |

## Keep the dashboard fresh

The integration does not sync automatically. If you don't run the exporter again, the dashboard keeps showing the data from the last export:

```shell theme={null}
docker compose --profile jobs run --rm exporter
```

Run this whenever you want fresh data.

<Accordion title="Automate exports on a schedule">
  If you want this to happen automatically, schedule the command above to run once per day. A crontab entry is the simplest option:

  ```shell theme={null}
  # User crontab (edit with crontab -e) — runs daily at 02:00
  0 2 * * * cd /path/to/text-metabase-integration && docker compose --profile jobs run --rm exporter
  ```

  A scheduled CI workflow can also run the export, but it must use a self-hosted runner that can access the same persistent Docker volumes as the Metabase stack.
</Accordion>

## Stop or reset

Stop the stack while keeping your data:

```shell theme={null}
docker compose down
```

Start it again the same way: `docker compose up -d`.

Remove all local data — the exported reports and the Metabase admin account and setup — and start from scratch:

```shell theme={null}
docker compose down -v
```

***

**Keep exploring**

<p>
  <Icon icon="file" /> [Reports API reference](/docs/api/reports/)
</p>
