To integrate Replit with Looker, store your Looker API client ID and client secret in Replit Secrets (lock icon π), use the Looker SDK to authenticate and run queries against Looker Explores, and embed dashboards or surface BI data in your application. Looker uses a client ID and client secret pair for API 4.0 authentication. Use an Autoscale deployment for dashboard data APIs and Reserved VM for scheduled report generation.
Looker API Integration for BI Data and Dashboard Embedding
Looker is Google Cloud's enterprise business intelligence platform, used by data teams to define metrics in LookML and expose them as governed, reusable queries. For application developers, the Looker API opens up powerful capabilities: run arbitrary queries against Looker Explores and get results as JSON, fetch saved Look results on demand, generate signed embed URLs so users can view Looker dashboards inside your application, and trigger data downloads in various formats. From Replit, these capabilities let you build data-rich applications that surface Looker analytics without users needing direct Looker access.
Looker's API authentication uses a client ID and client secret tied to a Looker user account. Each Looker user can generate API credentials from their account settings β these credentials have the same data access permissions as the user they belong to. For application integrations, create a dedicated Looker service account (a Looker user created specifically for API access) with the minimum data permissions needed. Store the client ID and client secret in Replit Secrets.
The Looker SDK for Python (looker-sdk) and the REST API (accessible from any language with an HTTP client) both support the same capabilities. The Python SDK is the most ergonomic choice for Replit Python projects. For Node.js projects, the @looker/sdk package provides equivalent functionality. Both SDKs handle the OAuth 2.0 token flow automatically β you provide credentials once and the SDK manages token generation and renewal.
Integration method
Looker integrates with Replit through the Looker API 4.0 using client ID and client secret authentication. Your Replit server exchanges credentials for an access token via the Looker SDK, then makes API calls to run queries, fetch Look results, download dashboards, and retrieve explore data. Looker's Python and Node.js SDKs handle token management automatically.
Prerequisites
- A Replit account with a Node.js or Python Repl ready
- A Looker instance (Google Cloud Looker or Looker's original cloud) with API access enabled
- A Looker user account with API credentials (Admin can generate these under Users β Edit User β API Credentials)
- Looker API access enabled on your Looker instance (Admin β General Settings β API)
- Python packages: looker-sdk, flask; Node.js packages: @looker/sdk, express
Step-by-step guide
Generate Looker API Credentials
Generate Looker API Credentials
Looker API credentials are generated per user from within the Looker application. The credentials consist of a Client ID and Client Secret that represent the Looker user's access. Log into your Looker instance. If you have Looker Admin access, navigate to Admin β Users and find the user (or create a new service account user) that will be used for API access. Click 'Edit' on the user, then scroll down to 'API Keys'. Click 'New API Key' to generate a client ID and client secret. Copy both values immediately β the secret is shown once. For production integrations, create a dedicated Looker user (e.g., 'replit-api-service') with a role that grants only the data permissions your integration needs. Avoid using an admin user's credentials for API integrations β if the credentials are compromised, a scoped role limits the blast radius. Note your Looker instance URL: it will be in the format https://yourcompany.looker.com (Looker cloud) or https://your-internal-looker-host.com (self-hosted). This URL is needed to initialize the Looker SDK. Also note whether your instance uses Looker API 4.0 (recommended, all current instances) or 3.1 (legacy). API 4.0 is the current standard and is what the SDK defaults to.
Pro tip: If you are using Google Cloud Looker (the newer Looker Studio platform), the API credentials and authentication differ. These instructions cover Looker (the original BI platform), not Looker Studio (Google Data Studio replacement).
Expected result: You have a Looker API client ID and client secret. You know your Looker instance URL. The API user has appropriate data permissions for the Explores you intend to query.
Store Looker Credentials in Replit Secrets
Store Looker Credentials in Replit Secrets
Click the lock icon (π) in the Replit sidebar to open the Secrets panel. Add the following secrets: LOOKER_BASE_URL: your Looker instance URL, e.g., https://yourcompany.looker.com. Include the protocol but no trailing slash. LOOKER_CLIENT_ID: the client ID from your Looker API credentials. LOOKER_CLIENT_SECRET: the client secret from your Looker API credentials. LOOKER_PORT: the Looker API port (typically 19999 for self-hosted instances, 443 for Looker cloud). If using Looker cloud, this may not be needed β the SDK will use port 443 by default. The Looker Python SDK can be configured using environment variables with specific names (LOOKERSDK_BASE_URL, LOOKERSDK_CLIENT_ID, LOOKERSDK_CLIENT_SECRET) or via a looker.ini file. Using Replit Secrets mapped to these SDK-specific variable names is the cleanest approach β the SDK will auto-configure from environment variables without any explicit initialization code. Replit's Secret Scanner monitors for credential patterns. Looker client secrets follow a specific format that the scanner may detect if accidentally included in code.
1# Option 1: SDK reads from standard Looker env vars (set these as Replit Secrets)2# LOOKERSDK_BASE_URL=https://yourcompany.looker.com3# LOOKERSDK_CLIENT_ID=your_client_id4# LOOKERSDK_CLIENT_SECRET=your_client_secret5# LOOKERSDK_VERIFY_SSL=true67# Option 2: Initialize SDK explicitly from custom secret names8import os9import looker_sdk10from looker_sdk import models40 as models1112# Configure SDK with credentials from Replit Secrets13sdk = looker_sdk.init40(14 base_url=os.environ['LOOKER_BASE_URL'],15 client_id=os.environ['LOOKER_CLIENT_ID'],16 client_secret=os.environ['LOOKER_CLIENT_SECRET']17)1819# Test connection20me = sdk.me()21print(f'Connected to Looker as: {me.display_name} ({me.email})')Pro tip: If you name your Replit Secrets exactly LOOKERSDK_BASE_URL, LOOKERSDK_CLIENT_ID, and LOOKERSDK_CLIENT_SECRET, the Looker Python SDK will auto-configure from them without any explicit initialization code.
Expected result: Looker credentials are stored in Replit Secrets. The initialization test connects successfully and prints the Looker user's display name.
Query Looker Explores and Looks with Python SDK
Query Looker Explores and Looks with Python SDK
The Looker Python SDK provides a comprehensive interface for running queries, fetching Look results, and accessing explore metadata. Install it in the Replit Shell: pip install looker-sdk flask. Two primary ways to fetch data from Looker: 1. Run inline query: construct a query with model, view, fields, filters, and limits, then call sdk.run_inline_query() to execute it immediately. 2. Fetch a Look: call sdk.run_look(look_id, result_format='json') to run a saved Look and get its results. For inline queries, the query object specifies which Looker Explore to query (model and view), which dimensions and measures to include (fields), and any filter conditions. The result_format parameter controls the output format β 'json' returns a list of row objects, 'json_detail' includes metadata, 'csv' returns comma-separated text. The Flask server below demonstrates both patterns with proper error handling. For production use, add caching to avoid running the same Looker query repeatedly β Looker queries can take several seconds to execute against large datasets.
1# looker_api.py β Looker API client for Replit (Python)2import os3import json4from flask import Flask, request, jsonify5import looker_sdk6from looker_sdk import models40 as models78# Initialize SDK from Replit Secrets9sdk = looker_sdk.init40(10 base_url=os.environ['LOOKER_BASE_URL'],11 client_id=os.environ['LOOKER_CLIENT_ID'],12 client_secret=os.environ['LOOKER_CLIENT_SECRET']13)1415app = Flask(__name__)1617@app.route('/api/query', methods=['POST'])18def run_query():19 """Run an inline Looker query."""20 body = request.get_json()21 22 try:23 query = models.WriteQuery(24 model=body['model'], # e.g., 'ecommerce'25 view=body['view'], # e.g., 'orders'26 fields=body.get('fields', []), # e.g., ['orders.count', 'orders.created_date']27 filters=body.get('filters', {}), # e.g., {'orders.status': 'complete'}28 limit=str(body.get('limit', 500))29 )30 31 results = sdk.run_inline_query('json', query)32 return jsonify(json.loads(results))33 34 except Exception as e:35 return jsonify({'error': str(e)}), 5003637@app.route('/api/looks/<int:look_id>')38def run_look(look_id):39 """Fetch results of a saved Looker Look."""40 result_format = request.args.get('format', 'json')41 42 try:43 results = sdk.run_look(look_id=look_id, result_format=result_format)44 if result_format == 'json':45 return jsonify(json.loads(results))46 else:47 return results, 200, {'Content-Type': 'text/csv'}48 except Exception as e:49 return jsonify({'error': str(e)}), 5005051@app.route('/api/dashboards/<int:dashboard_id>')52def get_dashboard_info(dashboard_id):53 """Get dashboard metadata and element list."""54 try:55 dashboard = sdk.dashboard(dashboard_id=str(dashboard_id))56 return jsonify({57 'title': dashboard.title,58 'description': dashboard.description,59 'element_count': len(dashboard.dashboard_elements or [])60 })61 except Exception as e:62 return jsonify({'error': str(e)}), 5006364if __name__ == '__main__':65 app.run(host='0.0.0.0', port=3000)Pro tip: Looker query results are returned as a JSON string, not a Python dict. Use json.loads(results) to convert the string to a Python object before returning it with jsonify().
Expected result: POST /api/query with model, view, and fields returns query results from Looker as JSON. GET /api/looks/123 returns the results of saved Look 123.
Fetch Looker Data from Node.js
Fetch Looker Data from Node.js
For Node.js Replit projects, the @looker/sdk package provides a JavaScript/TypeScript interface to the Looker API. Alternatively, you can use the Looker REST API directly with axios using token authentication. Install in the Replit Shell: npm install @looker/sdk @looker/sdk-node express. The @looker/sdk-node package provides the LookerNodeSDK that works in Node.js server environments (the @looker/sdk package alone is for browser use). Initialize it with your credentials from Replit Secrets. For simpler Node.js integrations, the REST API approach using axios is more straightforward: POST to /api/4.0/login with your client_id and client_secret to get an access token, then use the token in subsequent requests. This approach requires manual token refresh, while the SDK handles it automatically. The code below shows both patterns. The SDK approach is recommended for frequent API calls; the direct REST approach is fine for occasional queries.
1// looker.js β Looker API client for Replit (Node.js)2const axios = require('axios');3const express = require('express');45const LOOKER_BASE_URL = process.env.LOOKER_BASE_URL;6const CLIENT_ID = process.env.LOOKER_CLIENT_ID;7const CLIENT_SECRET = process.env.LOOKER_CLIENT_SECRET;89if (!LOOKER_BASE_URL || !CLIENT_ID || !CLIENT_SECRET) {10 throw new Error('Missing Looker credentials in Replit Secrets (lock icon π)');11}1213// Token cache14let accessToken = null;15let tokenExpiry = 0;1617async function getLookerToken() {18 if (accessToken && Date.now() < tokenExpiry - 30000) return accessToken;19 20 const response = await axios.post(`${LOOKER_BASE_URL}/api/4.0/login`, {21 client_id: CLIENT_ID,22 client_secret: CLIENT_SECRET23 });24 25 accessToken = response.data.access_token;26 tokenExpiry = Date.now() + (response.data.token_ttl * 1000);27 return accessToken;28}2930async function lookerRequest(method, path, data = null) {31 const token = await getLookerToken();32 const config = {33 method,34 url: `${LOOKER_BASE_URL}/api/4.0${path}`,35 headers: {36 Authorization: `token ${token}`,37 'Content-Type': 'application/json'38 }39 };40 if (data) config.data = data;41 const response = await axios(config);42 return response.data;43}4445const app = express();46app.use(express.json());4748// Run an inline query49app.post('/api/query', async (req, res) => {50 const { model, view, fields, filters, limit = 500 } = req.body;51 try {52 // Create query53 const query = await lookerRequest('POST', '/queries', { model, view, fields, filters, limit });54 // Run query55 const results = await lookerRequest('GET', `/queries/${query.id}/run/json`);56 res.json(results);57 } catch (err) {58 res.status(500).json({ error: err.response?.data || err.message });59 }60});6162// Get a Look's results63app.get('/api/looks/:lookId', async (req, res) => {64 try {65 const results = await lookerRequest('GET', `/looks/${req.params.lookId}/run/json`);66 res.json(results);67 } catch (err) {68 res.status(500).json({ error: err.response?.data || err.message });69 }70});7172app.listen(3000, '0.0.0.0', () => console.log('Looker Node.js server running on port 3000'));Pro tip: The Looker REST API uses 'token' (not 'Bearer') as the Authorization scheme: Authorization: token YOUR_ACCESS_TOKEN. Using 'Bearer' will result in a 401 error.
Expected result: POST /api/query returns Looker Explore results as a JSON array. GET /api/looks/123 returns the saved Look's current data. The token is cached and refreshed automatically.
Common use cases
Data API for Looker-Powered Dashboards
Build an Express or Flask API layer that runs Looker queries on request and returns results as JSON. Your frontend application calls this Replit API to get business metrics, chart data, and KPIs β without direct Looker access for end users. The Replit layer adds caching, authentication, and data transformation on top of raw Looker results.
Build a Flask API that accepts a metric name and date range, queries the corresponding Looker Explore using the Looker Python SDK, and returns aggregated results as JSON for a React dashboard.
Copy this prompt to try it in Replit
Embedded Dashboard Integration
Generate Looker SSO embed URLs from a Replit server to embed Looker dashboards in your application with signed authentication. Users view live, interactive Looker dashboards within your app's UI without needing their own Looker credentials.
Create an Express server that generates Looker signed embed URLs using the embed secret and returns them to the frontend, allowing authenticated users to view specific Looker dashboards embedded in the application.
Copy this prompt to try it in Replit
Scheduled Report Generator
Set up a Reserved VM Replit service that runs Looker queries on a schedule, formats the results into HTML or CSV reports, and distributes them via email or Slack. The service acts as a lightweight reporting automation layer on top of Looker's data.
Build a Python service that runs on a schedule, fetches weekly sales data from a Looker Look, formats it as a CSV, and sends it as an email attachment using SMTP β deploy as a Replit Reserved VM for continuous scheduling.
Copy this prompt to try it in Replit
Troubleshooting
401 Unauthorized when calling Looker API β 'Not authorized' error
Cause: The client ID or client secret is incorrect, or the Looker API is not enabled on your instance. Also occurs if the credentials belong to a user whose account is disabled.
Solution: In Looker Admin β Users, verify the API user account is active. Go to Edit User β API Keys to confirm the client ID matches what is in Replit Secrets. Re-generate API keys if uncertain. Also check Admin β General Settings β API is enabled for your Looker instance.
1# Test Looker login directly2import os, requests3response = requests.post(f'{os.environ["LOOKER_BASE_URL"]}/api/4.0/login', json={4 'client_id': os.environ['LOOKER_CLIENT_ID'],5 'client_secret': os.environ['LOOKER_CLIENT_SECRET']6})7print(response.status_code, response.json())ValidationError or 'Unknown model' when running inline queries
Cause: The model name, view name, or field names in your query do not match what exists in Looker. Looker model names are defined in LookML and are case-sensitive.
Solution: In Looker, navigate to the Explore you want to query. The URL shows the model and explore names: /explore/{model}/{explore}. Field names use the format {view_name}.{field_name}. Use the Looker API Explorer (in Admin β API Explorer) to test query construction interactively.
1// List available explores for a model to find correct names2const explores = await lookerRequest('GET', '/lookml_models/YOUR_MODEL_NAME/explores');3console.log('Available explores:', explores.map(e => e.name));Looker queries time out or take very long to return
Cause: Complex Looker queries against large datasets can take 10-30 seconds or longer. Replit's default request timeout may be too short, or the query is genuinely slow due to large data volume.
Solution: Add async query execution: use the Looker API's /queries endpoint to create a query, then poll /query_tasks/{id}/status until complete. This avoids HTTP timeout issues. Also consider adding filters to limit the query's data scope, or use Looker's caching (results are cached by default for 1 hour).
403 error accessing a specific Explore or Look β 'Access denied'
Cause: The Looker user account used for API credentials does not have permission to view the model, explore, or Look being queried. Looker uses roles and model permissions to control data access.
Solution: In Looker Admin β Roles, review the API user's role and its associated model sets. The model set must include the model you are trying to query. Ask your Looker Admin to add the appropriate model access to the API user's role.
Best practices
- Store LOOKER_BASE_URL, LOOKER_CLIENT_ID, and LOOKER_CLIENT_SECRET in Replit Secrets (lock icon π) β never hardcode these in source files
- Create a dedicated Looker service account for API integrations with a scoped role that grants only the model and data access the integration requires
- Cache Looker query results for at least the duration of Looker's own query cache (1 hour default) to avoid redundant computation on repeated requests
- Use the Looker Python SDK's init40() with explicit credentials rather than relying on a looker.ini file, which can be accidentally committed to version control
- Use run_inline_query for dynamic, parameterized queries and run_look for pre-defined, validated analyses that your data team has built in Looker
- Handle Looker query timeouts gracefully β use asynchronous query execution for complex queries that may exceed HTTP timeout limits
- Deploy data dashboard APIs as Autoscale for request-driven usage; use Reserved VM for scheduled report generation jobs that run on a fixed schedule
- Validate Looker model and field names against the Looker API Explorer before hardcoding them in your Replit application β names are case-sensitive and change when models are renamed
Alternatives
Tableau provides a similar REST API for querying workbooks and views, but is platform-agnostic rather than Google Cloud-native, making it a better choice for organizations not in the GCP ecosystem.
Power BI's REST API integrates deeply with the Microsoft ecosystem and Azure AD, making it preferable for organizations already using Microsoft 365 and Azure.
Vertex AI provides ML model prediction from the same Google Cloud ecosystem as Looker, useful when you want to combine Looker BI data with ML model predictions in the same Replit application.
Frequently asked questions
How do I connect Replit to Looker?
Generate API credentials in Looker (Admin β Users β Edit User β API Keys), store the client ID and client secret in Replit Secrets (lock icon π), and use the Looker Python SDK (pip install looker-sdk) or the REST API with axios. The SDK handles token authentication automatically when initialized with your credentials.
How do I securely store Looker API keys in Replit?
Click the lock icon (π) in the Replit sidebar and add LOOKER_BASE_URL, LOOKER_CLIENT_ID, and LOOKER_CLIENT_SECRET as separate secrets. Reference them in Python with os.environ['LOOKER_CLIENT_ID'] and in Node.js with process.env.LOOKER_CLIENT_ID. Never paste credentials directly into source code files.
Can I embed Looker dashboards in a Replit-hosted application?
Yes. Use the Looker Signed Embed URL feature: your Replit server generates a signed URL using the Looker embed secret and user attributes, returns it to your frontend, and the frontend renders it in an iframe. The embed secret is stored in Replit Secrets. This gives users access to interactive Looker dashboards within your application without direct Looker accounts.
Does Replit work with both Looker Cloud and Looker self-hosted?
Yes. The Looker API is the same whether your instance is Google Cloud Looker (hosted by Google) or self-hosted. The only difference is the base URL β for self-hosted instances, ensure Replit can reach your Looker server's URL (it must be publicly accessible or accessible from Replit's server IPs).
What deployment type should I use for a Looker integration on Replit?
Use Autoscale for dashboard APIs that serve data to users on demand β queries are stateless and scale-to-zero works well. Use Reserved VM for scheduled reporting jobs that run at fixed times (daily, weekly) to ensure the service is running at the scheduled time without cold start delays.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation