Skip to main content
RapidDev - Software Development Agency
lovable-integrationsEdge Function Integration

How to Integrate Lovable with Looker

To integrate Lovable with Looker, create a Supabase Edge Function that calls the Looker API using client ID and secret credentials stored in Cloud → Secrets. The Edge Function handles look execution, dashboard embedding via SSO URL generation, and query running. Use Lovable's chat to build embedded BI dashboards with secure SSO token generation and custom analytics interfaces.

What you'll learn

  • How to obtain Looker API client credentials and generate access tokens
  • How to implement Looker embed SSO URL generation in a Supabase Edge Function
  • How to store Looker credentials securely in Cloud → Secrets
  • How to embed secure Looker dashboards in a Lovable React app
  • How Looker's LookML approach differs from self-service BI tools like Microsoft Power BI
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced15 min read60 minutesBI/ReportingMarch 2026RapidDev Engineering Team
TL;DR

To integrate Lovable with Looker, create a Supabase Edge Function that calls the Looker API using client ID and secret credentials stored in Cloud → Secrets. The Edge Function handles look execution, dashboard embedding via SSO URL generation, and query running. Use Lovable's chat to build embedded BI dashboards with secure SSO token generation and custom analytics interfaces.

Embed Looker dashboards and run custom queries in Lovable with the Looker API

Looker is Google Cloud's enterprise BI platform centered on LookML — a data modeling language that defines metrics, dimensions, and relationships in a version-controlled codebase. The Looker API provides programmatic access to three categories of functionality: analytics execution (running Looks and ad-hoc queries), content management (dashboards, Looks, and scheduled deliveries), and embedded analytics (generating signed SSO URLs for secure external embedding).

The embed SSO pattern is the highest-value use case for Lovable integrations. Instead of giving end users direct Looker access (which requires Looker seats), you generate SSO URLs server-side that create temporary, scoped Looker sessions. Your users see a Looker dashboard embedded in your app without needing Looker accounts — the SSO token controls which dashboards they can access and what filters are pre-applied.

Looker is architecturally distinct from Microsoft Power BI. Power BI uses DAX and integrates tightly with the Microsoft ecosystem (Azure, Teams, Office). Looker uses LookML and is Google Cloud native with strong BigQuery integration. For Google Cloud infrastructure teams, Looker is the natural BI choice. For Microsoft-heavy organizations, Power BI's ecosystem integration makes more sense.

Integration method

Edge Function Integration

Looker API uses client ID and secret credentials to obtain short-lived access tokens for API calls. Embedded dashboard access uses SSO URL generation — a server-side process that creates signed URLs for embedding Looker dashboards in external applications. Both operations must happen in a Supabase Edge Function to keep Looker credentials and SSO signing secrets server-side.

Prerequisites

  • A Lovable account with a project that has Lovable Cloud enabled
  • A Looker instance (Looker Cloud or Looker core) with admin access
  • Looker API3 credentials — a client_id and client_secret generated in the Looker admin panel under Users → {your user} → Edit → API3 Keys
  • An embed secret configured in Looker Admin → Platform → Embed for SSO embedding
  • The hostname of your Looker instance — typically {company}.looker.com or {company}.cloud.looker.com

Step-by-step guide

1

Generate Looker API3 credentials and embed secret

Looker uses a two-credential system for API authentication. API3 credentials consist of a client_id and client_secret that are used to obtain a short-lived access token. These tokens are then used for all subsequent API calls. To generate API3 credentials, log into your Looker instance as an admin. Navigate to Admin → Users and click on your user account (or a service account user you create specifically for API access). Click 'Edit' and scroll to the 'API3 Keys' section. Click 'New API3 Key'. Looker generates a client_id and client_secret — copy both immediately, as the client_secret is only shown once. For the embed SSO functionality, you also need an embed secret. Navigate to Admin → Platform → Embed in your Looker instance. Enable Looker Embedding and note the embed secret (or generate a new one). This embed secret is used to sign SSO URLs server-side — it is different from the API3 credentials and is specifically for the iframe embedding feature. Also note your Looker instance hostname. If your Looker is accessed at company.looker.com, that is the hostname. For Looker Cloud instances, it may be company.cloud.looker.com. This hostname is used as the base URL for all API calls and embed URLs. Keep in mind that Looker API3 credentials are user-scoped — the API token inherits the permissions of the user whose credentials you use. For a dashboard embedding service account, create a dedicated Looker user with appropriate view permissions and generate API3 keys for that user.

Pro tip: Create a dedicated service account user in Looker for API access rather than using a personal user's credentials. This separates API access from individual user accounts and makes it easier to manage permissions and rotate credentials.

Expected result: You have a Looker API3 client_id, client_secret, an embed secret, and your Looker instance hostname. These four values are ready to store in Cloud → Secrets.

2

Store Looker credentials in Cloud → Secrets

Open your Lovable project and navigate to Cloud → Secrets via the '+' icon next to Preview. Add the following secrets: - Name: LOOKER_CLIENT_ID — Value: your API3 client_id - Name: LOOKER_CLIENT_SECRET — Value: your API3 client_secret - Name: LOOKER_EMBED_SECRET — Value: your embed secret from Admin → Platform → Embed - Name: LOOKER_HOST — Value: your Looker instance hostname (e.g., company.looker.com) All four secrets are required for the full integration. The client_id and client_secret authenticate API calls. The embed secret signs SSO URLs for secure dashboard embedding. The host value parameterizes all API endpoints and embed URL construction. Looker credentials provide access to your organization's business data — dashboards, reports, and query results may contain sensitive revenue, customer, or operational data. Apply strict access controls to these secrets.

Expected result: LOOKER_CLIENT_ID, LOOKER_CLIENT_SECRET, LOOKER_EMBED_SECRET, and LOOKER_HOST appear in Cloud → Secrets with masked values.

3

Create the Looker API proxy Edge Function with SSO URL generation

Create the Edge Function that handles three functions: obtaining Looker API tokens via client credentials, making API calls to run looks and queries, and generating SSO embed URLs for dashboard embedding. The API token flow: POST to https://{host}/api/4.0/login with client_id and client_secret to obtain a short-lived token. This token is used for all subsequent API calls in the same function invocation. The SSO URL generation flow is more complex. The SSO URL is constructed from the dashboard path, the viewer's identity (email and external_user_id), permissions, and a nonce and expiry. The URL is then signed using HMAC-SHA256 with the embed secret. Looker's embedding documentation specifies the exact parameter order for signing. The code below implements the complete Looker SSO URL signing process. It is the most technically involved part of this integration — pay careful attention to the parameter encoding and signing order.

Lovable Prompt

Create a Supabase Edge Function at supabase/functions/looker-api/index.ts with three capabilities: (1) obtain Looker API token via POST to /api/4.0/login with LOOKER_CLIENT_ID and LOOKER_CLIENT_SECRET; (2) run a Look by GET /api/4.0/looks/{look_id}/run/json; (3) generate a signed Looker SSO embed URL for a dashboard ID using the LOOKER_EMBED_SECRET and HMAC-SHA256 signing. Accept POST requests with 'action' (token | run_look | embed_url | dashboards) and params. Include CORS headers.

Paste this in Lovable chat

supabase/functions/looker-api/index.ts
1// supabase/functions/looker-api/index.ts
2async function getLookerToken(host: string, clientId: string, clientSecret: string): Promise<string> {
3 const response = await fetch(`https://${host}/api/4.0/login`, {
4 method: 'POST',
5 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
6 body: new URLSearchParams({ client_id: clientId, client_secret: clientSecret }),
7 });
8 const data = await response.json();
9 if (!data.access_token) throw new Error(`Looker login failed: ${JSON.stringify(data)}`);
10 return data.access_token;
11}
12
13async function generateEmbedSSOUrl(
14 host: string,
15 embedSecret: string,
16 dashboardId: string,
17 userEmail: string,
18 userId: string,
19 permissions: string[],
20 filters: Record<string, string> = {}
21): Promise<string> {
22 const nonce = crypto.randomUUID();
23 const time = Math.floor(Date.now() / 1000);
24 const sessionLength = 3600; // 1 hour
25
26 const embedPath = `/embed/dashboards/${dashboardId}`;
27 const filterParams = Object.keys(filters).length > 0
28 ? '?' + new URLSearchParams(filters).toString()
29 : '';
30
31 const params = [
32 `nonce=${encodeURIComponent(JSON.stringify(nonce))}`,
33 `time=${time}`,
34 `session_length=${sessionLength}`,
35 `external_user_id=${encodeURIComponent(JSON.stringify(userId))}`,
36 `permissions=${encodeURIComponent(JSON.stringify(permissions))}`,
37 `models=${encodeURIComponent(JSON.stringify([]))}`,
38 `group_ids=${encodeURIComponent(JSON.stringify([]))}`,
39 `external_group_id=${encodeURIComponent(JSON.stringify(''))}`,
40 `user_attributes=${encodeURIComponent(JSON.stringify({}))}`,
41 `access_filters=${encodeURIComponent(JSON.stringify({}))}`,
42 `first_name=${encodeURIComponent(JSON.stringify(userEmail.split('@')[0]))}`,
43 `last_name=${encodeURIComponent(JSON.stringify(''))}`,
44 `user_timezone=null`,
45 `force_logout_login=true`,
46 `url=${encodeURIComponent(embedPath + filterParams)}`,
47 ];
48
49 const stringToSign = `${host}\n${embedPath}\n${params.join('\n')}`;
50
51 const key = await crypto.subtle.importKey(
52 'raw',
53 new TextEncoder().encode(embedSecret),
54 { name: 'HMAC', hash: 'SHA-256' },
55 false,
56 ['sign']
57 );
58 const signature = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(stringToSign));
59 const signatureHex = Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, '0')).join('');
60
61 return `https://${host}/login/embed/${encodeURIComponent(embedPath)}?${params.join('&')}&signature=${signatureHex}`;
62}
63
64Deno.serve(async (req) => {
65 if (req.method === 'OPTIONS') {
66 return new Response(null, {
67 headers: {
68 'Access-Control-Allow-Origin': '*',
69 'Access-Control-Allow-Methods': 'POST, OPTIONS',
70 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
71 },
72 });
73 }
74
75 const clientId = Deno.env.get('LOOKER_CLIENT_ID')!;
76 const clientSecret = Deno.env.get('LOOKER_CLIENT_SECRET')!;
77 const embedSecret = Deno.env.get('LOOKER_EMBED_SECRET')!;
78 const host = Deno.env.get('LOOKER_HOST')!;
79
80 if (!clientId || !clientSecret || !host) {
81 return new Response(JSON.stringify({ error: 'Looker credentials not configured' }), {
82 status: 500,
83 headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
84 });
85 }
86
87 const { action, params } = await req.json();
88
89 try {
90 if (action === 'embed_url') {
91 const ssoUrl = await generateEmbedSSOUrl(
92 host, embedSecret,
93 params.dashboard_id,
94 params.user_email,
95 params.user_id,
96 params.permissions || ['access_data', 'see_user_dashboards'],
97 params.filters || {}
98 );
99 return new Response(JSON.stringify({ url: ssoUrl }), {
100 headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
101 });
102 }
103
104 const token = await getLookerToken(host, clientId, clientSecret);
105 const apiHeaders = { 'Authorization': `token ${token}`, 'Content-Type': 'application/json' };
106
107 let url: string;
108 if (action === 'dashboards') {
109 url = `https://${host}/api/4.0/dashboards`;
110 } else if (action === 'run_look') {
111 url = `https://${host}/api/4.0/looks/${params.look_id}/run/json`;
112 } else if (action === 'run_query') {
113 url = `https://${host}/api/4.0/queries/${params.query_id}/run/json`;
114 } else {
115 return new Response(JSON.stringify({ error: 'Invalid action' }), {
116 status: 400,
117 headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
118 });
119 }
120
121 const response = await fetch(url, { method: 'GET', headers: apiHeaders });
122 const data = await response.json();
123
124 return new Response(JSON.stringify(data), {
125 status: response.ok ? 200 : response.status,
126 headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
127 });
128 } catch (err) {
129 return new Response(JSON.stringify({ error: err.message }), {
130 status: 500,
131 headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
132 });
133 }
134});

Pro tip: Looker SSO URLs expire (default 1 hour). Generate a fresh SSO URL when the user navigates to the dashboard page — do not cache SSO URLs. Each URL is also single-use in some Looker configurations. The nonce in the signing ensures each URL is unique.

Expected result: The looker-api Edge Function is deployed. Calling it with { action: 'dashboards' } returns the list of Looker dashboards. Calling it with { action: 'embed_url', params: { dashboard_id, user_email, user_id } } returns a signed SSO URL.

4

Embed Looker dashboards in the Lovable React app

With the Edge Function generating SSO URLs, use Lovable's chat to build the embedded dashboard component. The component calls the Edge Function to get a fresh SSO URL, then renders a Looker iframe using that URL. Looker's embed SDK (available as @looker/embed-sdk on npm) provides better control over the embedded dashboard than a raw iframe — it supports events (dashboard:loaded, dashboard:run:complete), filter injection, and programmatic dashboard control. For basic embedding without the SDK, a raw iframe with the SSO URL is sufficient. For multi-dashboard portals, build a navigation sidebar that lists available dashboards (fetched from the Edge Function using action='dashboards') and updates the iframe src when the user selects a different dashboard. Each navigation triggers a new SSO URL generation for the selected dashboard. For user-context filtering — where each user should only see their own data — the filters parameter in the embed_url action pre-applies Looker filters to the embedded dashboard. The filter keys must match the field names in the Looker LookML model. For example, if the dashboard has a filter on the 'users.organization_id' dimension, pass filters: { 'users.organization_id': user.organization_id } to scope the dashboard to the current user's organization. For complex enterprise embedded analytics with multi-tenant data isolation, custom LookML development, and white-label BI portals, RapidDev's team can help design the full architecture including the Looker model configuration and Supabase user-attribute mapping.

Lovable Prompt

Build an analytics dashboard page that on mount calls the looker-api Edge Function with action='embed_url', the logged-in user's email and Supabase user ID, dashboard_id='1', and filters based on the user's organization_id from their profile. Display the returned URL in a full-height iframe. Show a loading spinner while the SSO URL is being generated and while the Looker dashboard loads. Add a refresh button that generates a new SSO URL and reloads the iframe.

Paste this in Lovable chat

src/components/LookerEmbed.tsx
1// src/components/LookerEmbed.tsx
2import { useState, useEffect } from 'react';
3import { supabase } from '@/lib/supabase';
4
5interface LookerEmbedProps {
6 dashboardId: string;
7 filters?: Record<string, string>;
8 height?: string;
9}
10
11export function LookerEmbed({ dashboardId, filters = {}, height = '80vh' }: LookerEmbedProps) {
12 const [embedUrl, setEmbedUrl] = useState<string | null>(null);
13 const [loading, setLoading] = useState(true);
14 const [error, setError] = useState<string | null>(null);
15
16 const generateUrl = async () => {
17 setLoading(true);
18 setError(null);
19 try {
20 const { data: { user } } = await supabase.auth.getUser();
21 if (!user) throw new Error('Not authenticated');
22
23 const { data, error: fnError } = await supabase.functions.invoke('looker-api', {
24 body: {
25 action: 'embed_url',
26 params: {
27 dashboard_id: dashboardId,
28 user_email: user.email,
29 user_id: user.id,
30 permissions: ['access_data', 'see_user_dashboards'],
31 filters,
32 },
33 },
34 });
35
36 if (fnError) throw fnError;
37 setEmbedUrl(data.url);
38 } catch (err) {
39 setError(err.message);
40 } finally {
41 setLoading(false);
42 }
43 };
44
45 useEffect(() => { generateUrl(); }, [dashboardId]);
46
47 if (loading) return <div className="flex items-center justify-center" style={{ height }}>Loading dashboard...</div>;
48 if (error) return <div className="text-red-500 p-4">Error: {error}</div>;
49
50 return (
51 <div className="w-full relative" style={{ height }}>
52 <iframe
53 src={embedUrl!}
54 className="w-full h-full border-0 rounded-lg"
55 allowFullScreen
56 title="Looker Dashboard"
57 />
58 </div>
59 );
60}

Pro tip: Add an iframe onLoad event handler that hides the loading spinner after the Looker dashboard finishes rendering — this prevents the spinner disappearing before the dashboard is actually visible.

Expected result: A Looker dashboard is embedded in the Lovable app inside an iframe. The dashboard loads with the correct user context and any pre-applied filters. The loading spinner disappears once the dashboard finishes rendering.

Common use cases

Embedded customer analytics portal

Build a customer portal where each customer can see their own analytics dashboard embedded from Looker. The Edge Function generates a Looker SSO URL scoped to the customer's organization ID, and the iframe in your Lovable app displays their filtered dashboard without any direct Looker access.

Lovable Prompt

Create a customer analytics page that calls the looker-api Edge Function to generate a Looker SSO embed URL for the currently logged-in user's organization. The SSO URL should pre-filter the dashboard to show only that customer's data. Display the Looker dashboard in a full-screen iframe. Show a loading spinner until the dashboard iframe loads.

Copy this prompt to try it in Lovable

Embedded executive dashboard with custom branding

Create an executive reporting page that embeds a pre-built Looker dashboard with your company's branding and custom navigation. The embed uses SSO to authenticate the viewer and apply their permission level, while the custom Lovable wrapper provides the navigation, header, and context that Looker's interface does not.

Lovable Prompt

Build an executive dashboard page with your company's branded header and navigation. Below the header, embed the Looker dashboard with ID 42 using a signed SSO URL from the looker-api Edge Function. Add a date range picker above the iframe that updates the Looker embed URL's filters when the date changes. The embed should fill the remaining viewport height.

Copy this prompt to try it in Lovable

Custom query runner and data export tool

Build a data exploration tool that lets analysts run custom queries against Looker's LookML model and export results to CSV or display them in a table. The tool uses the Looker Query API to execute inline queries and stream results back through the Edge Function.

Lovable Prompt

Create a query runner page where data analysts can select a LookML model and explore from a dropdown, add dimensions and measures from a checklist fetched from the Looker API, apply filters, and run the query via the looker-api Edge Function. Display results in a sortable table with a 'Export CSV' button. Show row count and query execution time.

Copy this prompt to try it in Lovable

Troubleshooting

SSO embed URL returns 'Invalid embed signature' when loaded in the iframe

Cause: The SSO URL signing order or encoding is incorrect. Looker's SSO URL signature is extremely sensitive to parameter order, encoding, and newline characters in the string to sign.

Solution: Compare your signing implementation against Looker's official embed documentation at docs.looker.com/reference/embed-api. Verify the string to sign uses the exact parameter order Looker specifies. Check that newlines in the string to sign are Unix newlines (\n) not Windows newlines (\r\n). Log the string to sign before hashing and compare it to a working example from Looker's documentation.

Looker API login returns 404 or 'Not Found' for the /api/4.0/login endpoint

Cause: The LOOKER_HOST value in Cloud → Secrets does not include the correct hostname, or your Looker instance uses a different API path.

Solution: Verify the LOOKER_HOST value is just the hostname without protocol or path — for example, company.looker.com not https://company.looker.com/api. Check your Looker instance's API explorer at https://{your-host}/api/4.0/ to confirm the API version and login endpoint path.

Embedded dashboard shows 'Session expired' or redirects to Looker login page

Cause: The SSO URL has expired (default 1 hour) or was already used (Looker invalidates nonces after use in some configurations).

Solution: Generate a fresh SSO URL each time the dashboard page is loaded — do not cache SSO URLs in localStorage or Supabase. Add a refresh button that calls the Edge Function to get a new URL and updates the iframe src. If sessions are expiring mid-session, increase the session_length parameter in the SSO URL generation, up to the maximum your Looker configuration allows.

Looker API returns 403 'Forbidden' or 'You do not have permission to perform this action'

Cause: The API3 credentials belong to a user without permission to access the requested resource, or the credentials have been revoked.

Solution: Log into Looker and verify the service account user's permissions include access to the dashboards and models you are querying. Navigate to Admin → Users → {service account user} → Roles to check assigned permissions. Also verify the API3 key has not been revoked — go to the user's profile and check the API3 Keys section shows active keys.

Best practices

  • Store all Looker credentials in Cloud → Secrets — they provide access to potentially sensitive business intelligence data that should never appear in browser code
  • Create a dedicated Looker service account user for API access with the minimum permissions needed — do not use an admin user's credentials for application API access
  • Generate fresh SSO URLs on each page load rather than caching them — SSO URLs have a defined expiry and may be single-use, making caching unreliable
  • Use Looker's user_attributes parameter in SSO URL generation to pass user context (like organization_id or region) that triggers row-level security filters in the LookML model
  • Request Looker API tokens freshly on each Edge Function invocation rather than storing them — tokens are short-lived and the login call is fast
  • Implement CORS correctly on the Edge Function since the iframe will load the Looker URL directly, but the SSO URL generation call from React goes through the Edge Function
  • Test SSO URL signing with Looker's embed test page at https://{your-host}/admin/embed/test before integrating with Lovable — this confirms the embed secret and signing parameters are correct

Alternatives

Frequently asked questions

Do end users of my Lovable app need Looker accounts to see embedded dashboards?

No — the Looker embed SSO pattern specifically enables external users to view Looker dashboards without Looker accounts. Your Lovable app generates a signed SSO URL server-side that creates a temporary, scoped Looker session for the viewer. The viewer sees the Looker dashboard inside an iframe but never interacts directly with Looker. This is the primary use case for embedded analytics: providing BI insights to customers or stakeholders who do not have and do not need Looker seats.

What is LookML and do I need to know it to use Looker's API?

LookML is Looker's data modeling language — it defines how your database tables map to business concepts (dimensions, measures, and relationships). You do not need to know LookML to use the Looker API for embedding or running existing Looks and dashboards. LookML is the responsibility of the data team that built and maintains the Looker instance. To use the API effectively, you need to know the IDs of the dashboards and Looks you want to embed, and the field names of filters you want to apply — your data team can provide these.

How is Looker different from Looker Studio (formerly Google Data Studio)?

Looker (formerly Looker Data Sciences, acquired by Google in 2019) is an enterprise BI platform with LookML data modeling, governance features, and programmatic API access. Looker Studio (formerly Google Data Studio) is a free, self-service visualization tool that connects to data sources like Google Sheets, BigQuery, and Analytics. They are different products that happen to share the Looker brand. The API described in this tutorial is for Looker (enterprise), not Looker Studio.

What permissions does the Looker embed SSO URL need?

The permissions parameter in the SSO URL generation controls what the embedded user can do. For read-only dashboard viewing, use ['access_data', 'see_user_dashboards']. To allow users to explore data and create their own queries, add 'explore'. To allow downloading data, add 'download_without_limit'. The permissions available depend on how your Looker instance is configured — check with your Looker admin for the permission names that correspond to the capabilities you want to enable for embedded users.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.