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.
When adding a new data source in Looker Studio the connector asks for:
- API URL (auth phase) — e.g.
https://plausible.example.com - API Key (auth phase) — bearer token from Plausible
- Site ID (config phase) — the domain as registered in Plausible (e.g.
example.com) - Custom Properties (config phase, optional) — comma-separated, e.g.
plan, account_type - Language Version Prefixes (config phase, optional) — comma-separated URL prefixes, e.g.
de-de, en-gb— creates theLanguage Versiondimension (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.
Prerequisites:
- Node.js installed
npm install -g @google/claspclasp 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 openclasp create automatically writes the Script ID into .clasp.json.
- Go to script.google.com → New project.
- Create these files (via the
+icon → Script) and paste in the matching content:Code.gsAuth.gsSchema.gsQuery.gsFilters.gsApi.gsUtil.gs
- Click the gear icon (Project Settings) → enable "Show 'appsscript.json' manifest file in editor".
- Open
appsscript.jsonand replace its contents with appsscript.json from this repo. - Save.
Prerequisite:
appsscript.jsonmust contain thedataStudioblock (seeappsscript.jsonin this repo), otherwise the connector will not be reachable from Looker Studio.
-
In the Apps Script editor, click the blue Deploy button at the top right.
-
From the dropdown select Test deployments.
-
The dialog shows the Head Deployment ID. Click the Copy icon next to it.
-
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. -
On the first run Looker Studio asks for authorization → click through.
-
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/queryToken API key from Plausible (Settings → API Keys → New API Key) Note: The path
/api/v2/querymust be included. The connector detects and strips it internally — it is not appended twice. -
Click Submit. The connector validates URL and key against the Plausible API.
-
In the configuration step enter the Site ID (e.g.
example.com), optional Custom Properties, and optional Language Version Prefixes → Connect. -
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.
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 requestsbounce_rateonly once from Plausible.
Note on revenue metrics:
total_revenueandaverage_revenueare 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.
- 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
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.
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/.
- Query — when a chart includes the
Language Versiondimension, the connector automatically adds a server-side Plausible filterevent: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. - Mapping — each returned page URL is matched against the prefix list.
The dimension value becomes
/de-de/(i.e. the prefix wrapped in slashes). - Aggregation — Looker Studio groups all rows with the same
Language Versionvalue and sums up the requested metrics. This produces one pie slice / table row per language version. - 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.
| 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.
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.
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.
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"(withoutgoalas 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.
-
Session metrics vs. event dimensions: Plausible forbids mixing
bounce_rate,visit_duration,views_per_visitwithpage/goalas 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 thegoaldimension 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_keystable 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;
2147483647is the maximum 32-bit integer and effectively disables the limit. To target a specific key only, add aWHEREclause, 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).
| 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 |
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.
- 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
forFilterOnlyfor its internal "Others" slice computation; the connector now detects this case via the pairedIS_NULLfilter inrequest.dimensionsFiltersand correctly includes the dimension in the Plausible query.
- Add: Language Version dimension — groups pages by configurable URL prefix (e.g.
/de-de/,/en-gb/), configurable per data source.
- Initial release.
GNU General Public License v3.0 — see LICENSE for the full license text.