# Looker Embedding Sso

> Guide for integrating Looker Single Sign-On (SSO) Embedding, including Gemini Insights (Conversational Analytics), Explore permissions, and Looker API 4.0 SSO URL generation. Use this skill when a user asks to embed a Looker dashboard, add Gemini to Looker iframe, or configure SSO embed permissions.

- Skill: `izzyfresh/looker-embedding-sso` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add izzyfresh/looker-embedding-sso`
- Raw SKILL.md: https://api.skillmd.com/api/skills/izzyfresh/looker-embedding-sso/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: IzzyFresh (https://skillmd.com/u/izzyfresh)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/izzyfresh/looker-embedding-sso

---


# Looker Embedding & SSO Guide

## Core Concepts

When embedding Looker dashboards into a frontend application (Node.js, Python, etc.), the backend must generate a signed SSO URL. This prevents users from having to log in to Looker directly.

### Looker API 4.0 SSO Generation

To generate an SSO URL natively via the Looker API:
1. Authenticate with `client_id` and `client_secret` to get a Bearer token.
2. Make a `POST` request to `/api/4.0/embed/sso_url`.

**Required Permissions Array:**
*   To view dashboards: `["access_data", "see_looks", "see_user_dashboards", "download_with_limit", "see_drill_overlay"]`
*   **To enable Self-Service / Explore Menus:** You MUST include `explore` and `embed_browse_spaces`. Without `embed_browse_spaces`, the user cannot navigate folders in the embed.
*   **To enable Clear Cache & Refresh:** Include `clear_cache_refresh`.
*   **To enable Gemini Insights (Conversational Analytics):** Include `chat_with_explore`, `gemini_in_looker`, and `chat_with_agent`.

### Gemini Insights Embed Path

To embed the native Looker Gemini Conversational Analytics experience:
**DO NOT** use the old extension path (`/embed/extensions/...`).
**DO** use the native conversational path:
```javascript
const target_url = `${LOOKER_BASE_URL}/embed/conversations`;
```

## Implementation Template (Node.js / Express)

```javascript
app.get('/api/looker/sso-url', async (req, res) => {
    const dashboardId = req.query.dashboard_id; // e.g. "14"
    const pathParam = req.query.path; // e.g. "/embed/conversations"
    
    let target_url = dashboardId ? 
        `${LOOKER_BASE_URL}/embed/dashboards/${dashboardId}` : 
        `${LOOKER_BASE_URL}${pathParam}`;

    const ssoBody = {
        target_url: target_url,
        session_length: 3600,
        force_logout_login: true,
        external_user_id: "embed_user_1",
        first_name: "Embed",
        last_name: "User",
        // Crucial permissions for Gemini and Explore
        permissions: [
            "access_data", "see_looks", "see_user_dashboards", "explore", 
            "download_with_limit", "clear_cache_refresh", "see_drill_overlay", 
            "save_content", "embed_browse_spaces", 
            "chat_with_explore", "gemini_in_looker", "chat_with_agent"
        ],
        models: ["your_model_name"], // Update this to match the LookML model!
        group_ids: [],
        external_group_id: "",
        user_attributes: {},
        access_filters: {}
    };
    
    const response = await axios.post(`${LOOKER_BASE_URL}/api/4.0/embed/sso_url`, ssoBody, {
        headers: { 'Authorization': `token ${looker_api_token}` }
    });
    
    res.json({ url: response.data.url });
});
```

## Pattern: Frontend Vanilla JS Iframe Embedding

When handling the frontend embedding, especially in a Single Page Application (SPA) or when toggling views, it is crucial to avoid refetching the SSO URL if the iframe is already loaded with a valid signed URL.

**The Fix:**
Always check if the iframe's `src` is completely empty OR if it lacks the `signature` parameter before fetching a new URL.

### Example (Vanilla JS)
```javascript
const iframe = document.querySelector('#my-looker-iframe');

// Correct Check: Only fetch if src is missing or doesn't have a signature
if (iframe && (!iframe.src || !iframe.src.includes('signature'))) {
    try {
        const res = await fetch('/api/looker/sso-url?dashboard_id=123');
        if (res.ok) {
            const data = await res.json();
            iframe.src = data.url;
        }
    } catch (err) {
        console.error('Error fetching SSO URL:', err);
    }
}
```

## Troubleshooting
- **Dashboard fails to load:** Check if the LookML model specified in the `models` array of the SSO payload matches the model the dashboard is built on.
- **Missing Options (Explore, Clear Cache):** Ensure `embed_browse_spaces` and `clear_cache_refresh` are in the permissions payload.

