Looker Studio Integration


The Looker Studio integration lets you build custom dashboards and reports in Google Looker Studio using your GrowPanel subscription data. Visualize MRR trends, customer counts, churn rates, and more — all in a tool your team may already be using.

GrowPanel provides a read-only API key that you use to pull data into Looker Studio. There are two ways to connect, depending on your preference.


Prerequisites

Before you start, enable the integration in GrowPanel:

  1. Go to Settings > Integrations
  2. Find the Looker Studio card and click Enable
  3. Copy the API Key and API Base URL from the modal — you'll need them in the steps below

The API key is only shown once when you enable the integration. If you lose it, click Remove on the Looker Studio card and enable it again to generate a new key.


Method 1: Via Google Sheets (recommended)

This is the easiest approach and works well for most teams. You use a small script to pull GrowPanel data into a Google Sheet, then connect that sheet to Looker Studio. The data refreshes automatically on a schedule you choose.

Step 1 — Create a Google Sheet

  1. Open Google Sheets and create a new spreadsheet
  2. Rename it to something descriptive, like "GrowPanel — MRR Data"

Step 2 — Add the import script

  1. In your spreadsheet, go to Extensions > Apps Script
  2. Delete any existing code and paste the following:
const API_KEY = 'YOUR_API_KEY_HERE';
const BASE_URL = 'https://api.growpanel.io';

function importMRR() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('MRR')
|| SpreadsheetApp.getActiveSpreadsheet().insertSheet('MRR');
fetchAndWrite(sheet, '/reports/mrr');
}

function importCustomers() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Customers')
|| SpreadsheetApp.getActiveSpreadsheet().insertSheet('Customers');
fetchAndWrite(sheet, '/customers');
}

function importSummary() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Summary')
|| SpreadsheetApp.getActiveSpreadsheet().insertSheet('Summary');
fetchAndWrite(sheet, '/reports/summary');
}

function importAll() {
importMRR();
importCustomers();
importSummary();
}

function fetchAndWrite(sheet, endpoint) {
const options = {
method: 'get',
headers: { 'Authorization': 'Bearer ' + API_KEY },
muteHttpExceptions: true
};

const response = UrlFetchApp.fetch(BASE_URL + endpoint, options);
if (response.getResponseCode() !== 200) {
Logger.log('Error fetching ' + endpoint + ': ' + response.getContentText());
return;
}

const json = JSON.parse(response.getContentText());
const data = json.result || json;

if (!Array.isArray(data) || data.length === 0) {
Logger.log('No data returned for ' + endpoint);
return;
}

const headers = Object.keys(data[0]);
const rows = data.map(row => headers.map(h => row[h] ?? ''));

sheet.clear();
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
if (rows.length > 0) {
sheet.getRange(2, 1, rows.length, headers.length).setValues(rows);
}

Logger.log('Imported ' + rows.length + ' rows into ' + sheet.getName());
}
  1. Replace YOUR_API_KEY_HERE with the API key you copied from GrowPanel
  2. Click Save (or Ctrl+S)

Step 3 — Run the script

  1. In the Apps Script editor, select importAll from the function dropdown
  2. Click Run
  3. The first time, Google will ask you to authorize the script — click through the prompts
  4. Switch back to your spreadsheet — you should see sheets named "MRR", "Customers", and "Summary" filled with data

Step 4 — Set up automatic refresh

  1. In the Apps Script editor, click the clock icon on the left sidebar (Triggers)
  2. Click + Add Trigger
  3. Set it up:
    • Function: importAll
    • Event source: Time-driven
    • Type: Hour timer (or Day timer for daily updates)
    • Interval: Every 4 hours (or your preference)
  4. Click Save

Your sheet will now refresh automatically.

Step 5 — Connect the sheet to Looker Studio

  1. Open Looker Studio
  2. Click Create > Data source
  3. Select the Google Sheets connector (built-in, no installation needed)
  4. Find and select your spreadsheet
  5. Choose the sheet tab you want (e.g., "MRR")
  6. Click Connect

You can now use this data source in any Looker Studio report. Repeat for each sheet tab you want to use.


Method 2: Community Connector (advanced)

This method creates a direct, live connection between Looker Studio and GrowPanel's API — no intermediate spreadsheet needed. It requires deploying a Google Apps Script project as a Looker Studio connector.

Step 1 — Create the connector project

  1. Go to Google Apps Script and click New project
  2. Rename the project to "GrowPanel Connector"
  3. Delete any existing code in Code.gs and paste the following:
var cc = DataStudioApp.createCommunityConnector();

function getAuthType() {
return cc.newAuthTypeResponse()
.setAuthType(cc.AuthType.KEY)
.setHelpUrl('https://growpanel.io/docs/settings/integrations/looker-studio/')
.build();
}

function setCredentials(request) {
PropertiesService.getUserProperties().setProperty('apiKey', request.key);
return { errorCode: 'NONE' };
}

function isAuthValid() {
var key = PropertiesService.getUserProperties().getProperty('apiKey');
if (!key) return false;
try {
var response = UrlFetchApp.fetch('https://api.growpanel.io/reports/summary', {
headers: { 'Authorization': 'Bearer ' + key },
muteHttpExceptions: true
});
return response.getResponseCode() === 200;
} catch (e) {
return false;
}
}

function resetAuth() {
PropertiesService.getUserProperties().deleteProperty('apiKey');
}

function getConfig() {
var config = cc.getConfig();
config.newSelectSingle()
.setId('endpoint')
.setName('Data to import')
.setHelpText('Choose which GrowPanel data to load')
.setAllowOverride(true)
.addOption(config.newOptionBuilder().setLabel('MRR over time').setValue('/reports/mrr'))
.addOption(config.newOptionBuilder().setLabel('MRR summary').setValue('/reports/summary'))
.addOption(config.newOptionBuilder().setLabel('Customers').setValue('/customers'))
.addOption(config.newOptionBuilder().setLabel('Movement table').setValue('/reports/movement-table'))
.addOption(config.newOptionBuilder().setLabel('Plans').setValue('/plans'))
.addOption(config.newOptionBuilder().setLabel('Leads').setValue('/reports/leads'));
config.setDateRangeRequired(false);
return config.build();
}

function getSchema(request) {
var key = PropertiesService.getUserProperties().getProperty('apiKey');
var endpoint = request.configParams.endpoint || '/reports/summary';
var data = fetchData(key, endpoint);
if (!data || data.length === 0) {
return { schema: [] };
}

var fields = Object.keys(data[0]).map(function(name) {
var sample = data[0][name];
var field = cc.newField()
.setId(name)
.setName(name);
if (typeof sample === 'number') {
field.setType(cc.FieldType.NUMBER);
} else {
field.setType(cc.FieldType.TEXT);
}
return field;
});

return cc.newGetSchemaResponse().setFields(fields).build();
}

function getData(request) {
var key = PropertiesService.getUserProperties().getProperty('apiKey');
var endpoint = request.configParams.endpoint || '/reports/summary';
var data = fetchData(key, endpoint);

var requestedFieldNames = request.fields.map(function(f) { return f.name; });
var rows = data.map(function(row) {
return {
values: requestedFieldNames.map(function(name) {
var val = row[name];
return val !== undefined && val !== null ? val : '';
})
};
});

var fields = request.fields.map(function(f) {
var sample = data.length > 0 ? data[0][f.name] : '';
var field = cc.newField()
.setId(f.name)
.setName(f.name);
if (typeof sample === 'number') {
field.setType(cc.FieldType.NUMBER);
} else {
field.setType(cc.FieldType.TEXT);
}
return field;
});

return cc.newGetDataResponse()
.setFields(fields)
.addAllRows(rows)
.build();
}

function fetchData(apiKey, endpoint) {
var response = UrlFetchApp.fetch('https://api.growpanel.io' + endpoint, {
headers: { 'Authorization': 'Bearer ' + apiKey },
muteHttpExceptions: true
});
if (response.getResponseCode() !== 200) {
cc.newUserError()
.setText('API returned status ' + response.getResponseCode())
.throwException();
}
var json = JSON.parse(response.getContentText());
return json.result || json;
}

Step 2 — Update the manifest

  1. In the left sidebar, click Project Settings (gear icon)
  2. Check Show "appsscript.json" manifest file in editor
  3. Go back to the editor and open appsscript.json
  4. Replace its contents with:
{
"timeZone": "America/New_York",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"dataStudio": {
"name": "GrowPanel",
"description": "Connect GrowPanel subscription analytics to Looker Studio",
"company": "GrowPanel",
"logoUrl": "https://growpanel.io/images/growpanel-icon.png",
"addonUrl": "https://growpanel.io/docs/settings/integrations/looker-studio/",
"supportUrl": "https://growpanel.io/docs/settings/integrations/looker-studio/"
}
}
  1. Click Save

Step 3 — Deploy the connector

  1. Click Deploy > New deployment
  2. Click the gear icon next to "Select type" and choose Add-on
  3. Add a description (e.g., "GrowPanel connector v1")
  4. Click Deploy
  5. Copy the Deployment ID — you'll need it next

Step 4 — Use the connector in Looker Studio

  1. Open Looker Studio
  2. Click Create > Data source
  3. Search for "GrowPanel" in the connector list, or click Build your own and enter your Deployment ID
  4. When prompted, paste your GrowPanel API key
  5. Choose which data to import (MRR over time, Customers, etc.)
  6. Click Connect

You now have a live data source that Looker Studio queries directly from GrowPanel's API.


Available data

Both methods give you access to the same GrowPanel API endpoints. Here are the most useful ones for reporting:

EndpointDescriptionExample fields
/reports/mrrMRR over timedate, mrr, customers
/reports/summaryCurrent period summarynew_mrr, churned_mrr, net_mrr, total_mrr
/customersCustomer listname, email, status, current_mrr, plan
/reports/movement-tableMRR movements by monthdate, new, expansion, contraction, churn, reactivation
/reports/leadsTrial and lead metricsdate, new_leads, conversions
/plansActive plansname, billing_freq, currency

For the complete list, see the API reference.


Refreshing data

  • Google Sheets method: Data refreshes on the schedule you set in Apps Script Triggers (e.g., every 4 hours). Looker Studio picks up changes automatically when the sheet updates.
  • Community Connector method: Looker Studio caches data for up to 15 minutes by default. You can click the refresh icon in any report to fetch the latest data.

Revoking access

To disconnect:

  1. Go to Settings > Integrations in GrowPanel
  2. Click Remove on the Looker Studio card

This revokes the API key immediately. Any connected Looker Studio reports or Google Sheets scripts using that key will stop receiving data. You can enable the integration again at any time to generate a new key.


Troubleshooting

IssueSolution
"Authorization failed" in Looker StudioCheck that you pasted the full API key, including all three dot-separated parts
Google Sheets script returns no dataOpen Apps Script, run importAll manually, and check the Execution log for errors
Data looks stale in Looker StudioClick the refresh icon in your report, or check that your Sheets trigger is running
Lost your API keyClick Remove on the Looker Studio card in GrowPanel, then click Enable to generate a new key
"API returned status 401"Your API key may have been revoked. Generate a new one in GrowPanel