Skip to content

Repository files navigation

Plausible CE Connector for Looker Studio

A Google Looker Studio (formerly Data Studio) Community Connector that connects a self-hosted Plausible Community Edition instance.

  • Talks directly to the Plausible Stats API v2 (POST /api/v2/query)
  • Exposes all Plausible metrics & dimensions in Looker Studio
  • Translates Looker filters (INCLUDE/EXCLUDE, EQUALS, IN_LIST, CONTAINS, REGEX) including AND/OR into Plausible filters
  • Custom Properties (event:props:*) configurable as first-class fields
  • Goals filterable (e.g. goal = "Generate Lead") — also as a behavioural filter (has_done)
  • Language Version dimension — groups pages by URL prefix (e.g. /de-de/, /en-gb/) configurable per data source

Note

This project was built with Claude Code to cover my own reporting needs. Some combinations of dimensions or metrics may be untested, missing, or broken. Feel free to fork the project and adapt it for your own setup.


Setup

When adding a new data source in Looker Studio the connector asks for:

  1. API URL (auth phase) — e.g. https://plausible.example.com
  2. API Key (auth phase) — bearer token from Plausible
  3. Site ID (config phase) — the domain as registered in Plausible (e.g. example.com)
  4. Custom Properties (config phase, optional) — comma-separated, e.g. plan, account_type
  5. Language Version Prefixes (config phase, optional) — comma-separated URL prefixes, e.g. de-de, en-gb — creates the Language Version dimension (see Language Version dimension)

API URL + key are stored per Looker user (PropertiesService.getUserProperties) and are reusable across multiple data sources. Site ID is per data source.

Deployment

Variant A: clasp (recommended for developers)

Prerequisites:

  • Node.js installed
  • npm install -g @google/clasp
  • clasp login
# One-time inside the project folder: create a new Apps Script project
clasp create --type standalone --title "Plausible CE Connector" --rootDir .

# After making changes
clasp push

# Open in the browser
clasp open

clasp create automatically writes the Script ID into .clasp.json.

Variant B: manually via the Apps Script editor

  1. Go to script.google.comNew project.
  2. Create these files (via the + icon → Script) and paste in the matching content:
    • Code.gs
    • Auth.gs
    • Schema.gs
    • Query.gs
    • Filters.gs
    • Api.gs
    • Util.gs
  3. Click the gear icon (Project Settings) → enable "Show 'appsscript.json' manifest file in editor".
  4. Open appsscript.json and replace its contents with appsscript.json from this repo.
  5. Save.

Test the connector in Looker Studio

Prerequisite: appsscript.json must contain the dataStudio block (see appsscript.json in this repo), otherwise the connector will not be reachable from Looker Studio.

  1. In the Apps Script editor, click the blue Deploy button at the top right.

  2. From the dropdown select Test deployments.

  3. The dialog shows the Head Deployment ID. Click the Copy icon next to it.

  4. Open a new browser tab with the URL:

    https://lookerstudio.google.com/datasources/create?connectorId=<DEPLOYMENT_ID>
    

    Replace <DEPLOYMENT_ID> with the value copied in step 3.

  5. On the first run Looker Studio asks for authorization → click through.

  6. A form with two fields appears — the generic labels are "Username" and "Token":

    Field What to enter
    Username Full API URL of the Plausible instance including the path, e.g. https://plausible.example.com/api/v2/query
    Token API key from Plausible (Settings → API Keys → New API Key)

    Note: The path /api/v2/query must be included. The connector detects and strips it internally — it is not appended twice.

  7. Click Submit. The connector validates URL and key against the Plausible API.

  8. In the configuration step enter the Site ID (e.g. example.com), optional Custom Properties, and optional Language Version PrefixesConnect.

  9. Fields appear — start building your report.

Tip: The Head Deployment ID stays stable across clasp push cycles, so you can bookmark the Looker Studio link once and reuse it.

Available fields

Metrics

visitors, visits, pageviews, views_per_visit, bounce_rate, engagement_rate, visit_duration, events, scroll_depth, time_on_page, conversion_rate, group_conversion_rate, percentage

Engagement Rate is a derived metric and not a native Plausible API value. It is computed client-side as the inverse of bounce_rate: engagement_rate = 1 − bounce_rate. Example: Bounce Rate 60 % → Engagement Rate 40 %. When both metrics are used in the same chart, the connector still requests bounce_rate only once from Plausible.

Note on revenue metrics: total_revenue and average_revenue are not available in Plausible Community Edition — they require Plausible Cloud with paid Revenue Goals. The fields are kept commented out in Schema.gs and can be re-enabled if a future CE release exposes them.

Dimensions

  • Time: date, hour, week, month
  • Event: page, hostname, goal
  • Visit: entry_page, exit_page, source, referrer, channel, utm_medium, utm_source, utm_campaign, utm_content, utm_term, device, browser, browser_version, os, os_version, country, country_name, region, region_name, city, city_name
  • Custom Properties (dynamic, per config): appear as Property: <name>
  • Language Version (dynamic, per config): appears as Language Version — see below

Language Version dimension

Plausible has no native concept of audience segments or language versions. The Language Version dimension is a computed dimension that the connector derives from the event:page URL path by matching configurable prefixes.

Configuration

In the data-source configuration form, enter the URL prefixes without leading or trailing slashes, comma-separated:

de-de, en-gb, fr-fr

This creates a single Language Version dimension in Looker Studio with possible values /de-de/, /en-gb/, /fr-fr/.

How it works

  1. Query — when a chart includes the Language Version dimension, the connector automatically adds a server-side Plausible filter event:page matches [^/de-de/, ^/en-gb/, ...]. Only pages whose path starts with one of the configured prefixes are returned by the API — no extra data is transferred.
  2. Mapping — each returned page URL is matched against the prefix list. The dimension value becomes /de-de/ (i.e. the prefix wrapped in slashes).
  3. Aggregation — Looker Studio groups all rows with the same Language Version value and sums up the requested metrics. This produces one pie slice / table row per language version.
  4. Skipping — rows whose page URL does not match any prefix (e.g. / or a page outside all language prefixes) are excluded entirely from the response, so they do not appear as an unnamed segment.

Example: pie chart "Pageviews by language version"

Setting Value
Chart type Pie chart
Dimension Language Version
Metric pageviews
(optional) Date range as needed

No calculated field or manual filter is required in Looker Studio.

Combining with other dimensions

Language Version can be used alongside other dimensions (e.g. source, device). When combined with page, both share the same underlying event:page Plausible dimension — the connector deduplicates automatically so the API is not asked twice for the same column.

Filtering by language version

Chart-level or report-level filters on the Language Version field are forwarded to Plausible as event:page filters. Use EQUALS or IN_LIST to include/exclude specific versions, or CONTAINS/REGEXP_PARTIAL_MATCH for pattern-based filtering.

Filters

Looker Studio filters are translated automatically:

Looker Plausible
EQUALS (INCLUDE) is
EQUALS (EXCLUDE) is_not
IN_LIST is / is_not with multiple values
CONTAINS contains / contains_not
REGEXP_PARTIAL_MATCH / REGEXP_EXACT_MATCH matches / matches_not
AND/OR logic ["and", [...]] / ["or", [...]]

Examples:

  • goal = "Generate Lead"["is", "event:goal", ["Generate Lead"]]
  • goal = "Generate Lead" (without goal as a dimension) → ["has_done", ["is", "event:goal", ["Generate Lead"]]]
  • country IN_LIST [DE,AT,CH] (EXCLUDE) → ["is_not", "visit:country", ["DE","AT","CH"]]
  • Property: plan = "pro"["is", "event:props:plan", ["pro"]]

Filters that Plausible does not support directly (e.g. IS_NULL, numeric operators on metrics) are dropped — the connector then sets filtersApplied: false and Looker filters client-side instead.

Known limitations

  • Session metrics vs. event dimensions: Plausible forbids mixing bounce_rate, visit_duration, views_per_visit with page/goal as dimensions. The connector forwards the 400 error from Plausible with an explanation in Looker.

  • Conversion metrics (conversion_rate, total_revenue) only return meaningful values when a goal filter or the goal dimension is involved.

  • Rate limit: Plausible allows 600 requests per hour per API key by default. On a self-hosted CE instance the limit is stored per-key in the api_keys table and can only be changed via direct database access — there is no env variable or admin UI for it (see discussion #1573):

    # Connect to the Plausible Postgres container (adjust the container name to your setup)
    docker exec -it plausible_plausible_db_1 psql -U postgres
    
    # Raise the limit for ALL keys (or filter by id / name to target a single key)
    UPDATE public.api_keys SET hourly_request_limit = 2147483647;

    2147483647 is the maximum 32-bit integer and effectively disables the limit. To target a specific key only, add a WHERE clause, e.g. WHERE name = 'Looker Studio Connector'.

  • Pagination: Up to 100,000 rows per Looker refresh (10 × 10,000), guarding against the Apps Script timeout (6 min).

Architecture

File Responsibility
Code.gs Connector entry points: getConfig, getSchema, getData, isAdminUser
Auth.gs USER_TOKEN flow, credential validation, reset
Schema.gs Static + dynamic field definitions, Looker field building
Query.gs Plausible request body construction, response mapping
Filters.gs Translation dimensionsFilters → Plausible filter DSL
Api.gs HTTP wrapper with bearer auth, pagination, error mapping
Util.gs Date helpers, property storage, string parsing
appsscript.json Apps Script manifest with dataStudio block

Naming convention: trailing underscore

Function names ending with _ are an Apps Script convention for private functions. The runtime treats them specially:

  • They do not appear in the "Run function" dropdown in the editor
  • They are not exposed when the script is used as a library (see Libraries — Best practices)
  • They are not callable from google.script.run
  • They are not valid web-app entry points

This produces a clean two-tier visibility model:

Visibility Examples Meaning
No _ getAuthType, getConfig, getSchema, getData, setCredentials, resetAuth, isAuthValid, isAdminUser Looker Studio entry points — the framework calls them by exact name. Renaming any of them silently breaks the connector.
Trailing _ plausibleQuery_, loadCredentials_, translateFilters_, buildQuery_, convertMetricValue_, … Internal helpers. Not part of the public surface.

When adding a new helper, give it a trailing underscore unless Looker Studio is meant to call it.

Changelog

0.0.3

  • Fix: Pie charts (and other slice-limited charts) with "Number of slices" set below the actual data row count now render correctly. Looker Studio marks the grouping dimension as forFilterOnly for its internal "Others" slice computation; the connector now detects this case via the paired IS_NULL filter in request.dimensionsFilters and correctly includes the dimension in the Plausible query.

0.0.2

  • Add: Language Version dimension — groups pages by configurable URL prefix (e.g. /de-de/, /en-gb/), configurable per data source.

0.0.1

  • Initial release.

License

GNU General Public License v3.0 — see LICENSE for the full license text.

About

A Google Looker Studio (formerly Data Studio) Community Connector that connects a self-hosted Plausible Community Edition instance.

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages