Vibe monitoring with Last9 MCP: Ask your agent to fix production issues! Setup →
Last9 Last9

How to Get Grafana Iframe Embedding Right

Know how to securely embed Grafana dashboards using iframes, covering auth, config, performance, and monitoring with Last9.

Jul 14th, ‘25
How to Get Grafana Iframe Embedding Right
See How Last9 Works

Unified observability for all your telemetry. Open standards. Simple pricing.

Talk to us

Adding Grafana dashboards directly into your app lets users see monitoring data without switching tabs or tools. Using an iframe to embed Grafana does work, but it brings along some tricky authentication and security issues that aren’t always obvious at first.

In this blog, we’ll go over the practical ways to embed Grafana dashboards from easy public snapshots to secure, private dashboards that need authentication.

Pick the Right Way to Embed Grafana

There are four main ways to embed a Grafana dashboard in your app. Each has its own trade-offs around security, performance, and user experience.

1. Embed Public Dashboards (Fastest to Set Up)

For dashboards that don’t show sensitive data, you can use Grafana’s public dashboard option. This gives you a live, interactive view that’s easy to embed using a simple iframe.

<iframe 
  src="https://your-grafana-instance.com/public-dashboards/abc123?from=now-6h&to=now" 
  width="100%" 
  height="400px" 
  frameborder="0">
</iframe>

To enable this:

  • Go to the dashboard → Share → Public dashboard
  • Toggle the switch
  • Copy the generated iframe code

Note: Anyone with the link can access the data. So, only use this for public or non-sensitive dashboards.

2. Use Snapshots for Read-Only Embeds

Snapshots create a static version of your dashboard at a specific point in time. They're still interactive (you can hover and explore panels), but they don’t update with new data.

<iframe 
  src="https://snapshots.raintank.io/dashboard-solo/snapshot/xyz789" 
  width="100%" 
  height="400px" 
  frameborder="0">
</iframe>

Good for:

  • Incident reports
  • Weekly status updates
  • Sharing dashboards without hitting data sources

You can publish snapshots to Grafana’s public snapshot server or keep them internal.

3. Embed Private Dashboards with Authentication (More Secure, More Setup)

If your dashboards are private, users will hit a login screen inside the iframe unless you handle authentication. To even allow this kind of embedding, you need to tweak the Grafana config:

[security]
allow_embedding = true
cookie_samesite = lax
  • allow_embedding = true disables the X-Frame-Options: deny header, which normally blocks Grafana from loading in iframes
  • cookie_samesite = lax helps session cookies work across your app and Grafana, especially if they’re on the same root domain

Without these settings, browsers will block the embed or break session handling.

4. Use the API to Build a Custom Dashboard View

For full control, no iframes, no login prompts, you can pull dashboard data from Grafana’s API and render it inside your own frontend.

Step 1: Get an API token

  • Go to Administration → Users and access → Service accounts
  • Create a service account with read permissions
  • Generate a token

Step 2: Fetch dashboard data

const response = await fetch(`https://your-grafana-instance.com/api/dashboards/uid/${dashboardUid}`, {
  headers: {
    'Authorization': `Bearer ${serviceAccountToken}`
  }
});
const dashboardData = await response.json();

You’ll need to handle the visualization logic yourself (charts, layout, filters, etc.), but this gives you:

  • A seamless UX
  • Full control over authentication and design
  • Flexibility to integrate with other app data
💡
If you're running into login or session issues while embedding, this guide on fixing Grafana login problems can help.

Config Settings You’ll Need for Self-Hosted Grafana Embeds

If you’re hosting Grafana yourself, a few config tweaks are needed to get iframe embedding working smoothly, especially if you're dealing with authentication, cross-origin requests, or public access.

Update Your grafana.ini File

Start by adjusting these core settings:

[security]
allow_embedding = true
cookie_samesite = lax

[panels]
disable_sanitize_html = true
  • allow_embedding = true: Allows Grafana to be loaded inside an iframe by disabling the X-Frame-Options: deny header.
  • cookie_samesite = lax: Makes sure session cookies work when Grafana is embedded on a related domain or subdomain.
  • disable_sanitize_html = true: Only needed if you're embedding third-party HTML inside a Grafana panel (like in the Text panel). You don’t need this if you're just embedding Grafana itself elsewhere.

Enable Anonymous Access (Optional)

If you want people to view dashboards without logging in—say for public status pages or internal tools—you can turn on anonymous access:

[auth.anonymous]
enabled = true
org_name = Main Org
org_role = Viewer

This lets unauthenticated users access dashboards with the permissions of a "Viewer" in the specified org. Combine this with network-level restrictions to avoid exposing sensitive data.

Configure CORS and Security Headers (If Needed)

When your Grafana instance and the app embedding it are on different domains, browsers can block cross-origin requests unless you explicitly allow them. Add the following to handle CORS properly:

[security]
allow_embedding = true
cors_allow_credentials = true
cors_allowed_origins = https://your-app.com
  • cors_allow_credentials = true: Ensures cookies are sent with cross-origin requests
  • cors_allowed_origins: Should point to the origin where your application is hosted
💡
To better control data resolution in your embedded dashboards, understanding the Grafana rate() function is useful.

What You Can and Can’t Do with Grafana Cloud

If you're using Grafana Cloud, there’s a key limitation to know:
You can’t enable allow_embeddingso embedding private, authenticated dashboards isn’t supported.

That’s a deliberate design choice for security reasons. The managed service doesn’t let you tweak this config.

Here’s what does work:

  • Public dashboards – Same setup as self-hosted. If your data is safe to share publicly, you can embed it with an iframe.
  • Dashboard snapshots – Good for sharing point-in-time views without live data.
  • API-based embedding – Fetch dashboard data using Grafana’s API and render it yourself inside your app.

In short: with Grafana Cloud, embedding works for public or read-only use cases, but not for authenticated dashboards.

Customize Grafana Embeds with URL Parameters

Grafana lets you modify embedded dashboards and panels using query parameters. This gives you fine-grained control over time ranges, themes, layout, refresh intervals, and variable inputs, directly from the embed URL.

from and to: Define Custom Time Ranges

You can set the dashboard's time window using from and to parameters in the URL:

<iframe 
  src="https://your-grafana-instance.com/d-solo/dashboard-id/panel-name?from=now-24h&to=now" 
  width="100%" 
  height="400px">
</iframe>

Common formats:

  • from=now-1h&to=now — Last hour
  • from=now-7d&to=now — Last 7 days
  • from=1609459200000&to=1609545600000 — Absolute timestamps (in milliseconds)

theme, kiosk, refresh: Control UI and Behavior

Use these parameters to adjust the appearance and behavior of the embedded view:

<iframe 
  src="https://your-grafana-instance.com/d-solo/dashboard-id/panel-name?theme=dark&kiosk=1&refresh=30s" 
  width="100%" 
  height="400px">
</iframe>
  • theme=dark or theme=light — Switch between dark and light modes
  • kiosk=1 — Hide navigation bars for a cleaner display
  • refresh=30s — Enable auto-refresh at the specified interval

var-*: Pass Dashboard Variable Values

You can set Grafana template variables via URL to dynamically control what data is shown:

?var-hostname=server1

This is especially useful when embedding the same dashboard for different hosts, environments, or services.

d-solo and panelId: Embed Specific Panels

To embed just one panel instead of the full dashboard, use the d-solo path and include the panelId parameter:

<iframe 
  src="https://your-grafana-instance.com/d-solo/dashboard-id/panel-name?panelId=2" 
  width="100%" 
  height="300px">
</iframe>

This approach works well for breaking up dashboards and displaying specific metrics in different parts of your UI.

💡
If you're using the API-based embedding approach, this guide on getting started with the Grafana API covers the basics.

Design Responsive Grafana Embeds

When embedding Grafana dashboards in your app, they need to scale well across different screen sizes, from wide desktop monitors to mobile devices. Here’s how to handle responsive behavior effectively.

Use CSS for Dynamic Sizing of the Iframe

Wrapping your iframe in a container and applying responsive CSS ensures it adapts to various viewports:

<div class="dashboard-container">
  <iframe 
    src="https://your-grafana-instance.com/d-solo/dashboard-id/panel-name" 
    width="100%" 
    height="400px"
    style="min-height: 300px;">
  </iframe>
</div>

<style>
.dashboard-container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

@media (max-width: 768px) {
  .dashboard-container iframe {
    height: 300px;
  }
}
</style>
  • width: 100% ensures the iframe stretches to fit its container
  • max-width keeps it from overflowing on large displays
  • Media queries adjust height for smaller screens

Adjust Time Ranges and Content for Mobile Devices

Dashboards that look fine on a desktop may become unreadable on mobile. To improve usability:

  • Limit the number of panels shown on smaller screens
  • Use broader time ranges (e.g., 1h instead of 5m) to reduce visual noise
  • Provide a full-screen or expand option for complex views

You can also dynamically adjust iframe parameters based on screen size:

// Detect screen size and adjust time range
const isMobile = window.innerWidth < 768;
const timeRange = isMobile ? 'from=now-1h&to=now' : 'from=now-6h&to=now';

const iframeSrc = `https://your-grafana-instance.com/d-solo/dashboard-id/panel-name?${timeRange}`;

Inject this iframeSrc into your app’s DOM to serve a mobile-optimized view when needed.

Authentication Strategies for Embedded Grafana Dashboards

If you need to embed private or authenticated Grafana dashboards, a standard iframe won’t be enough. You’ll need to handle user auth in a way that balances security, usability, and integration effort. Here are two patterns that teams commonly use.

Pattern 1: Use a Backend Proxy for Authentication

Set up a proxy server that handles authentication with Grafana. Your application takes care of authenticating the user, and the proxy injects valid credentials when making requests to Grafana.

// Your app authenticates the user
const userToken = await authenticateUser(request);

// Your proxy injects this token when talking to Grafana
const grafanaResponse = await proxyToGrafana(dashboardUrl, userToken);

Why this works well:

  • Keeps authentication logic on the server (not exposed to the browser)
  • Avoids exposing tokens in iframe URLs
  • Gives you more control over session management, headers, and cookie behavior

This is the go-to option for embedding private dashboards in production-grade apps.

Pattern 2: Embed Service Account Tokens in URLs (Use with Caution)

For internal tools or low-sensitivity use cases, you can pass a service account token directly in the iframe URL:

<iframe 
  src="https://your-grafana-instance.com/d-solo/dashboard-id?auth_token=your_service_token" 
  width="100%" 
  height="400px">
</iframe>

Important caveats:

  • The token is visible in browser dev tools and network traffic
  • Anyone with access to the token URL can reuse it
  • Best reserved for internal apps with strong network-level access controls

While easy to set up, this method trades off security for speed, so use it only when you understand and can accept the risks.

💡
Now, debug embedded Grafana dashboards faster with Last9 MCP—bring real-time logs, metrics, and traces into context to fix issues right from your IDE.

Common Embedding Issues and How to Fix Them

Embedding Grafana dashboards in your app can run into browser quirks, security headers, and network configurations. Here’s a breakdown of the most frequent problems and how to solve them.

1. SameSite Cookie Restrictions Break Authentication

Modern browsers limit third-party cookies by default. If your app and Grafana are on different domains, the browser might block Grafana's session cookies, causing login issues inside iframes.

Fix:
Set the following in grafana.ini:

[security]
cookie_samesite = lax

For best results, serve your app and Grafana from the same domain or subdomain to avoid cross-site cookie issues entirely.

2. X-Frame-Options Blocking the Embed

Even if you set allow_embedding = true, some reverse proxies (like NGINX or cloud security layers) may override it by adding X-Frame-Options: DENY to HTTP responses.

Fix:
Check your proxy, CDN, or web server configs for extra security headers that might block iframe rendering. Remove or override any conflicting X-Frame-Options.

3. Service Account Token Expiry

If you're using tokens to authenticate embeds (e.g., in iframe URLs or API calls), they may expire and cause dashboards to fail silently or throw auth errors.

Fix:

  • Use long-lived tokens for internal environments
  • Or build token refresh logic into your backend

4. Embedded Dashboards Slow Down Page Load

Grafana dashboards can be heavy multiple panels, queries, and data loads that can slow down your app if loaded all at once.

Fix:

  • Lazy-load iframes only when they're visible (e.g., using IntersectionObserver)
  • Show placeholders or skeleton UIs until the user interacts with the section

5. CORS Errors on Cross-Domain Embeds

If your app and Grafana run on different origins, CORS restrictions may block resource loading or API calls.

Fix:
In grafana.ini, set:

[security]
allow_embedding = true
cors_allow_credentials = true
cors_allowed_origins = https://your-app.com

Make sure the origin matches exactly, including protocol (https://).

6. Inconsistent Behavior Across Browsers

Some browsers handle iframes more strictly, especially when it comes to cookies, JavaScript execution, and Content Security Policy (CSP).

Fix:

  • Test embeds in Chrome, Firefox, Safari, and Edge
  • Pay attention to:
    • Third-party cookie behavior
    • How each browser enforces CSP headers
    • JS functionality inside the iframe
💡
To pass dynamic values into your embedded dashboards, this guide on Grafana variables breaks down how to use them effectively.

Performance Optimization for Embedded Grafana Dashboards

Embedding dashboards can increase page load times and memory usage, especially with multiple panels or real-time data updates. These optimization strategies can help keep performance under control.

Lazy Load Dashboards Using IntersectionObserver

Avoid loading dashboards until they're visible in the viewport. This reduces initial load time and avoids unnecessary network or rendering work.

// Lazy load dashboards only when they enter view
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const iframe = entry.target;
      iframe.src = iframe.dataset.src;
      observer.unobserve(iframe);
    }
  });
});

document.querySelectorAll('iframe[data-src]').forEach(iframe => {
  observer.observe(iframe);
});

This is especially effective when multiple dashboards are embedded on a single page or behind tabs/expandable sections.

Implement Client-Side Caching for Repeated Loads

If you’re fetching dashboard data manually (via API), use a local in-memory cache to avoid repeated network calls:

// Simple cache for dashboard data
const dashboardCache = new Map();

async function loadDashboard(dashboardId) {
  if (dashboardCache.has(dashboardId)) {
    return dashboardCache.get(dashboardId);
  }
  
  const response = await fetch(`/api/dashboards/${dashboardId}`);
  const data = await response.json();
  
  // Cache for 5 minutes
  dashboardCache.set(dashboardId, data);
  setTimeout(() => dashboardCache.delete(dashboardId), 300000);
  
  return data;
}

This reduces load on your backend and speeds up repeat visits to the same dashboards.

Monitor Dashboard Load and Resource Usage

Use the browser's PerformanceObserver API to measure load times and track how much time embedded dashboards take to render:

const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    if (entry.name.includes('grafana')) {
      console.log(`Dashboard load time: ${entry.duration}ms`);
    }
  });
});

observer.observe({ entryTypes: ['navigation', 'resource'] });

This helps identify heavy dashboards and optimize the layout or data queries accordingly.

Security Best Practices for Embedded Dashboards

Embedding monitoring dashboards into your app surface exposes internal data, latency, error rates, and service health to a broader audience. Here’s how to do it without opening up unnecessary risk.

Enforce HTTPS for All Resources

Always serve both your application and Grafana over HTTPS.

Mixed content (HTTPS page embedding HTTP iframe) will:

  • Trigger browser security warnings
  • Block dashboard loads entirely in modern browsers

Secure transport also protects tokens, cookies, and session data in transit.

Apply Fine-Grained Access Controls

Embedding doesn't bypass authentication requirements. Users still need to be authorized to view the data.

Recommendations:

  • Restrict access to private dashboards using role-based access in Grafana
  • Apply user-level permissions in your own application layer before rendering embeds
  • Avoid hardcoding public links unless the data is truly non-sensitive

Rotate Service Account Tokens Regularly

If you use tokens for authentication (e.g., via API or iframe URLs), treat them as secrets:

  • Rotate tokens on a regular schedule
  • Store them securely (avoid exposing them in frontend code or logs)
  • Revoke tokens if no longer needed

Even internal-use tokens can leak through browser tools or developer environments.

Monitor Access Patterns and API Usage

Embedded dashboards can be scraped or accessed programmatically. Use monitoring to detect:

  • Unusually high request volumes
  • Requests from unexpected IPs or geographies
  • API token usage patterns that don’t match user behavior

Grafana logs and reverse proxy logs can help here. You can also set rate limits or IP-based restrictions on your endpoints.

💡
If you're embedding dashboards powered by Prometheus, this Prometheus and Grafana setup guide covers the key integration steps.

Conclusion

Embedding Grafana dashboards isn’t just a UI decision; it’s part of your observability surface. You’re exposing telemetry data to end users, which makes performance, access control, and reliability critical.

At Last9, we help teams go beyond basic embeds. Our managed observability platform handles high-cardinality metrics at scale, integrates seamlessly with Prometheus and OpenTelemetry, and connects dashboards to logs and traces, so you can debug slow loads, auth errors, and data issues without guesswork.

If you’re embedding dashboards, monitor them like any other production component. With Last9, you get full visibility without the cost spikes.

Get started with us today!

FAQs

How to embed the next app to WP blog?

While this guide focuses on Grafana embedding, the same iframe principles apply to Next.js apps. Export your Next.js app as static files, host them, and embed using an iframe. For WordPress, use the HTML block to add iframe code, ensuring your hosting allows iframe embedding.

How do I handle authentication for embedded Grafana dashboards? Authentication is the trickiest part of Grafana embedding. You have several options: enable anonymous access for public dashboards, use service account tokens in URLs for internal apps, implement proxy authentication to handle auth server-side, or use API-based approaches with custom authentication flows.

Can I use an iframe?

Yes, iframe is the primary method for embedding Grafana dashboards. You need allow_embedding = true in your Grafana configuration to remove X-Frame-Options restrictions. However, iframes aren't supported in Grafana Cloud for private dashboards due to security policies.

What are the performance implications of embedding Grafana dashboards? Embedded dashboards can slow page load times, especially with complex queries or many panels. Optimize by using lazy loading, limiting data points, setting appropriate refresh intervals, and considering placeholder content until users interact with the dashboard.

Is it public with no authentication? It depends on your setup. Public dashboards and snapshots are accessible without authentication. Private dashboards require authentication, which creates login prompts in iframes. Anonymous access can be enabled for internal applications, but this removes access controls.

Why Integrate Grafana into Your Web Application? Integrating Grafana dashboards into your application provides users with monitoring data without context switching. It creates a unified experience where operational metrics sit alongside application features, improving workflow efficiency and data accessibility for your team.

How can I embed a Grafana dashboard in my website using an iframe? First, ensure allow_embedding = true that in your Grafana configuration. Then use standard iframe HTML with your dashboard URL. For public dashboards, use the Share → Public dashboard option. For private dashboards, you'll need to handle authentication separately.

How do I embed a Grafana dashboard in an iframe on my website? Navigate to your Grafana dashboard, click Share → Embed, and copy the provided iframe code. Make sure your Grafana instance has allow_embedding = true configured. Paste the iframe code into your website's HTML where you want the dashboard to appear.

How can I customize the appearance of a Grafana dashboard embedded via iframe? Use URL parameters to customize embedded dashboards: theme=dark for dark mode, kiosk=1 to hide navigation, from=now-1h&to=now for time ranges, and var-hostname=server1 for dashboard variables. For deeper customization, consider API-based approaches with custom rendering.

Authors
Anjali Udasi

Anjali Udasi

Helping to make the tech a little less intimidating. I

Contents

Do More with Less

Unlock high cardinality monitoring for your teams.