Grafana image rendering service for reports and alert images: when your team needs it
If your shared, self-hosted Grafana has to send dashboard images, PDFs or CSV files to people who do not log in, you need the Grafana Image Renderer, a separate service that Grafana calls to turn panels and dashboards into files. According to the Grafana image rendering docs, the renderer produces PNG, PDF and CSV output and works with Grafana OSS, Enterprise and Cloud, so the edition you run does not decide whether the service is available. The renderer is not a plugin you switch on inside Grafana. The Grafana 13.0 upgrade guide removes support for running it as a plugin, so it must be deployed as its own process that Grafana reaches over the network.
Plan the host before you plan the feature. The Grafana image rendering docs state that the renderer needs at least 16 GiB of memory and 4 CPU cores, which is far above the 2 cores and 2 to 4 GB of RAM the installation docs give for a small Grafana server. Budget that capacity for the renderer alone, and confirm with your own load that concurrent exports at your busiest reporting time stay within it. Alert images depend on the same service, so a renderer outage affects notifications as well as scheduled reports. Ask your team which alert rules must include an image and what happens to those notifications if the renderer is unavailable.
Settle the edition question before you promise reports to the business. Scheduled PDF delivery in the open-source edition is a separate question from the renderer itself, because the renderer produces the files but scheduling and distribution features depend on what your edition provides. Confirm with Grafana which report scheduling options are available in your edition and version, and whether the renderer alone covers the exports your stakeholders need. Doing this check early avoids building a renderer deployment that does not match the delivery workflow the business expects.
Configuration options and when each one fits
This table compares the main deployment and configuration choices for the renderer and shows which volume of reports and alert images each one suits. Read each row against your expected export load, your hosting model and whether the renderer already runs as its own service. From Grafana 13.0 onward, the renderer must run as a separate service, so the decision is about how to host it, not whether to host it separately.
| Option | What it involves | When it fits | What to confirm |
|---|---|---|---|
| Docker container | Renderer runs from a container image beside Grafana, with settings passed as environment variables or container arguments | Teams already running Grafana in containers who want the renderer versioned and replaced with the same tooling | Image tag matches your Grafana version and the host has at least 16 GiB of memory and 4 CPU cores for the renderer |
| Packaged binary on a VM | Renderer installed on a virtual machine as a service next to Grafana, managed by the host's init system | Teams running Grafana on VMs who prefer one operating system process model and standard host patching | Chromium dependencies install cleanly on your distribution and the service restarts after host reboots |
| Single renderer | One renderer instance that all Grafana requests reach directly | Low volume of scheduled reports and occasional alert images where a short queue is acceptable | Peak report runs do not overlap with alert evaluation windows |
| Renderer pool behind a load balancer | Several renderer instances behind one address that Grafana calls | High volume of scheduled exports, many dashboards with many panels, or alert images needed during incidents | Load balancer health checks and the shared token are applied to every instance |
| Renderer URL and callback URL | The renderer address Grafana calls, and the address the renderer uses to reach Grafana when it loads dashboards | Every deployment, and the callback URL changes whenever Grafana sits behind a proxy or in a separate network segment | Renderer can reach Grafana at the callback address and Grafana can reach the renderer at the renderer address |
| Timeouts and concurrency | Limits on how long a render may run and how many renders may run at once | Tune when large dashboards time out or when renders queue during busy periods | Timeout values chosen from observed render durations in your environment, not from defaults alone |
| Renderer token | Shared secret set in the rendering section of grafana.ini and in the renderer, enabled by default in Grafana 13.0 | Every deployment, since the token authenticates Grafana to the renderer | Token is non-default, stored in a secrets manager and rotated with both sides restarted |
Deploying the renderer and connecting it to Grafana
This sequence takes a host from the renderer's stated resource minimums to a running Grafana instance that produces PNG, PDF and CSV exports and alert images. Each step ends with a check you can run before moving on.
Size the renderer host against the minimums
Before anything is installed, confirm that the host reserved for the renderer has at least 16 GiB of memory and 4 CPU cores, as the Grafana image rendering documentation states for the renderer. Confirm this with your platform team, since the renderer runs separately from Grafana and needs its own capacity. Also decide where the renderer runs relative to Grafana, so that Grafana can reach its URL over the network. The step is complete when the host specification is written down and approved, and when you can show that the host meets the stated minimums.
Deploy the renderer as a separate container
Run the Grafana Image Renderer as its own service, because the Grafana 13.0 upgrade guide removes support for running it as a Grafana plugin. Deploy the renderer image with Docker or your container platform, keeping it on a network segment that Grafana can reach. Confirm the image tag against the image rendering setup page and record it in your change log. The check is that the renderer container is running, stays up after a restart, and answers on its listening port from the Grafana host.
Set a non-default renderer token in Grafana
In Grafana, set a value for renderer_token in the [rendering] section of the configuration file. The Grafana 13.0 upgrade guide notes that the renderAuthJWT toggle is on by default and requires this token to be non-default and shared with the renderer. Generate a long random value, store it in your secrets manager, and do not reuse a value from another system. Restart Grafana so the setting loads. The check is that Grafana starts without configuration errors and that the token is not visible in the instance's settings page or logs.
Configure the matching token on the renderer
Set the same token value on the renderer so that the two services authenticate each other. The token must match exactly, so copy it from the same secrets store and avoid manual retyping. Use the exact keys and variables listed in the Grafana image rendering setup documentation for your renderer version. Restart the renderer after the change. The check is that the renderer logs show it started with authentication enabled and that no mismatch errors appear when Grafana sends it a request.
Point Grafana at the renderer URL
Set the renderer URL in the [rendering] section of Grafana's configuration so that Grafana knows where to send render requests. Use the address that the Grafana server can resolve and reach, which may differ from the address you use in a browser. If Grafana sits behind a reverse proxy or runs in a separate container network, confirm the route in both directions. The check is a direct connection test from the Grafana host to the renderer endpoint, which should return a healthy response without a timeout.
Confirm a test PNG export from the interface
Open a dashboard in Grafana, choose the option to share or export a panel as an image, and generate a PNG. Confirm that the image shows the panel data and not an error or blank frame. If the render fails, check the Grafana log for the request and the renderer log for the matching entry, since token mismatches and network blocks usually appear in one or the other. The check is a PNG file that opens and displays the expected panel content.
Confirm test PDF and CSV exports
Export a dashboard as PDF and a panel's data as CSV from the Grafana interface. The renderer produces PDF and PNG files, while CSV exports depend on the data returned by the panel's query. Open each file and compare it with what the dashboard shows at the same time range. The check is that the PDF contains all expected panels and that the CSV matches the query results, which confirms the path from Grafana to the renderer for each export format.
Send a test alert image to a notification channel
Create a test alert rule with a notification channel that supports images, such as email or a chat integration your team already uses, and make the rule fire on demand. Confirm that the notification includes a rendered image of the panel. Ask the notification vendor whether your chosen channel supports embedded images before relying on it for production alerts. The check is a received notification that contains the image, which confirms the renderer serves alert notifications as well as manual exports.
What changed for the renderer in Grafana 13
Grafana 13.0 changes how the Grafana Image Renderer can be deployed. Support for running the renderer as a Grafana plugin has been removed, so the renderer must run as a separate service that Grafana calls over the network. If your current instance renders PNG, PDF or CSV exports through the plugin, treat the move to a standalone renderer as a required migration step rather than a configuration tweak. Plan it as a change in its own right: decide where the renderer will run, who owns its container or host, how it gets patched, and how Grafana will reach it before you start the Grafana upgrade. The Grafana 13.0 upgrade guide is the starting point for that plan.
The second change is authentication. The renderAuthJWT toggle is on by default in Grafana 13, which means Grafana signs requests to the renderer with a token. That only works if you set a non-default [rendering] renderer_token value in the Grafana configuration and configure the renderer with the same shared secret. Generate the token from your secrets management process, not from a default in a sample file, and store it where your deployment tooling can rotate it. Expect a failed render or an alert image with no picture as the usual symptom of a mismatched or missing token, so test an export from the dashboard and a test alert notification after every change.
Before upgrading, confirm the exact sequence for your target version against its release notes, since upgrade steps can differ between patch and minor releases. Check whether your installed renderer version is compatible, whether the environment variables or configuration keys you use are still read, and whether your deployment automation sets the renderer address and token. Rehearse the sequence on a non-production copy of the instance, including a render of a dashboard that uses your real data sources and an alert that sends an image. Keep the previous Grafana package and configuration available so you can roll back if the renderer connection fails after the cutover.
Securing the token, network path and rendered data
The renderer holds a shared secret, reaches into your dashboards and produces files that can leave Grafana. Each control below closes one of those paths, and together they keep the renderer from becoming a side door around the permissions you set in Grafana. Review them before the renderer receives its first production request.
Keep the renderer token secret
With the renderAuthJWT toggle on by default in Grafana 13, Grafana and the renderer must share a non-default renderer_token under the [rendering] section. Store that value in a secrets manager or an environment variable injected at deploy time, and keep it out of grafana.ini, Helm values and Git repositories. Check that the token is not echoed in logs, container inspection output or CI job traces, and plan a rotation procedure that updates both sides together.
Limit which hosts can reach the renderer
The renderer should accept connections only from the Grafana servers that call it. Use network policies, security groups or host firewall rules to allow the renderer's listening port from Grafana's addresses and deny everything else, including other application subnets. Confirm the path with a test request from a host that is not Grafana and expect it to fail. Note that the token protects requests, but network restriction limits who can attempt them.
Keep the renderer off public networks
Do not publish the renderer through a public load balancer, ingress or reverse proxy, even for testing. The renderer loads dashboard URLs and returns rendered content, so an exposed instance widens the attack surface for every dashboard it can display. Place it on an internal segment reachable only from the Grafana tier, and verify the absence of public DNS records and ingress routes during the review.
Treat exports as dashboard data
A PNG, PDF or CSV produced through the renderer carries the data the requesting user could already see in Grafana. Confirm that the export path respects the same folder and data source permissions, and that exported files are stored and shared under the same rules as the dashboards they came from. Plan retention and deletion for generated files, and limit who can download them from report or export workflows.
Review what alert images reveal
Alert notification images render the panel at the moment an alert fires, so they can expose metric values, host names and labels to every contact point that receives them. Chat channels, email lists and third-party paging services may have wider audiences than the dashboard. Compare each contact point's audience with the panel's data sensitivity, and remove or redact panels that show restricted values before attaching them to alerts.
Patch the renderer with Grafana
Track renderer releases alongside Grafana minor and patch releases, and test the pair in a non-production environment before rollout. Grafana publishes patch releases at least monthly, so the renderer should sit in the same change calendar, with a documented version pairing and a rollback path. Ask who receives security advisories for the renderer image and how quickly your team can deploy a fix.
Questions teams ask before running the renderer
What drives the cost of setting up the image renderer?
Most of the cost is labor for sizing, placement, token configuration, export testing and handover, plus the infrastructure the renderer runs on. The Grafana docs state that the renderer needs at least 16 GiB of memory and 4 CPU cores, so that capacity is a recurring hardware or cloud line. Costs rise with the number of concurrent exports, dashboard complexity, the number of Grafana instances sharing one renderer, and the environment, since air-gapped and regulated networks add review and change control. Ask any quote to list the environments in scope, the number of instances, the test cases, the documentation delivered and what is excluded. Ongoing upgrades and monitoring of the renderer are usually recurring work, so confirm whether they are included.
How long does a basic renderer deployment take?
The duration depends mostly on how familiar your team is with containers, container networking and Grafana administration. Teams that already run containers and manage Grafana settings can usually move through installation and token setup quickly, while teams new to containers spend more time on image management, service-to-service networking and secrets handling. Testing across real dashboards and alert rules adds time that is easy to underestimate. This page does not give a duration because the answer depends on your environment, so ask for a timeline in the written scope, with the assumptions about skills, environments and approvals stated.
What does the renderer project need from our team?
Prepare these items before the work starts:
- A host or container platform with at least 16 GiB of memory and 4 CPU cores reserved for the renderer.
- Network rules that let the Grafana server reach the renderer, with the renderer kept off public networks and limited to the outbound access it needs.
- A generated renderer token stored in your secrets manager, with a named owner for rotation.
- A test dashboard using panels from your real data sources, plus one alert rule that sends a notification with an image.
- A change window and access to Grafana administration for configuration and restart.
DeployOpen can work within these inputs, but your team should confirm who approves network changes and who holds the secrets, since those decisions affect the rest of the plan.
Can an internal team deploy the renderer without a partner?
Yes, an internal team can deploy it if it has solid container skills and administers Grafana already. The installation and configuration steps are documented, and the main risks are misconfigured token authentication, undersized hosts and forgotten upgrade steps. A partner adds the most value when the scope covers several Grafana instances, air-gapped or regulated networks, a documented runbook for operators, or test evidence for an assessment. Whichever route you choose, write down who owns the renderer after go-live, who responds when exports fail, and how upgrades are scheduled, because those responsibilities decide whether the service keeps working.
How do alert images differ from scheduled PDF reports?
An alert image is a rendered picture of a panel that Grafana attaches to an alert notification when the rule fires, so it reflects the state at the time of the alert. A scheduled PDF report is a rendered export of a dashboard that is produced on a timetable and delivered to recipients. Both rely on the same renderer, but they have different failure modes: alert images depend on the notification channel accepting an attachment or image link, and reports depend on the schedule and delivery path. Confirm with each contact point whether it can carry images, and test one alert and one report end to end before relying on either. Scheduled reporting features in Grafana Enterprise are a separate option that should be compared on its own terms.
What changes when moving from a Grafana 12 plugin install to Grafana 13?
In Grafana 13.0, support for running the Image Renderer as a Grafana plugin is removed, so the renderer must run as a separate service. The renderAuthJWT toggle is on by default, which means Grafana and the renderer must share a non-default [rendering] renderer_token. Before upgrading, deploy the separate renderer, configure the shared token on both sides, and test PNG, PDF and CSV exports plus alert images in a staging instance. Remove the old plugin only after those tests pass, and check the Grafana 13.0 upgrade guide for other changes that apply to your instance.
How should the renderer be secured on our network?
Keep the renderer on a private network segment that only the Grafana servers can reach, and do not publish it to the internet. Token authentication means the renderer accepts requests only from a Grafana instance holding the shared renderer_token, so store that token in your secrets manager, restrict who can read the Grafana configuration, and plan a rotation procedure. Because the renderer loads dashboard URLs to draw them, limit its outbound network access to the data sources and Grafana endpoints it needs. Your security team should review these settings against your own policies and record the decisions in the change request.
Which Grafana editions can use the image renderer?
The Grafana Image Renderer works with Grafana open source, Grafana Enterprise and Grafana Cloud, according to the Grafana image rendering docs. The edition decides which other features are available, so the choice of edition should be made on the full set of requirements, not on the renderer alone. Open-source deployments can run the renderer as a separate service and use it for PNG, PDF and CSV exports and alert images. Confirm your edition's licensing terms with Grafana Labs before you commit, since licensing details can change.
Sizing the renderer for report and alert volume
Size the renderer as its own workload, not as an extension of the Grafana server. The Grafana Image Renderer documentation sets a floor of 16 GiB of memory and 4 CPU cores for the renderer, and that figure sits apart from the small-deployment guidance for the Grafana server in the installation docs, which describes 2 cores and 2 to 4 GB of RAM for fewer than 25 concurrent users. Each render starts a headless browser, loads the dashboard, waits for panels to query their data sources and then draws the image, so the renderer carries the browser cost while the server carries the dashboard and query logic. Budget the two tiers separately, and check the renderer host against the documented floor before you consider any other capacity question.
Load rises with the work each image requires. The main drivers are the number of panels rendered into one image, the size and query cost of the dashboard, how often scheduled reports run and how many images a single alert storm can request at once. A full-width dashboard with many time series panels takes longer and holds more memory than a single panel, and a report that fires for many recipients at the same hour creates a burst that can exceed the average load. Alert notifications are often the less visible source of bursts, because a shared outage can trigger many rules together. Ask your team to list the top ten dashboards by panel count and the report schedules that share a start time, since those two lists explain most of the peak.
Reserve headroom above the documented floor and test with real dashboards before production. Use copies of your heaviest dashboards, render them at the time ranges your users choose, and watch memory, CPU and render duration while several renders run together. If you run reports and alerts at the same time, include both in the test. Confirm the current guidance for concurrency and timeouts in the image rendering documentation for your version, because those settings determine whether a burst queues or fails. Treat the results as the basis for the production sizing and repeat the test after any major change to dashboards or Grafana itself.
Trade-offs of a separate renderer service
Running the Grafana Image Renderer outside the Grafana server adds a component to operate, but it moves heavy browser work onto its own host. The cards below cover the decisions that follow from that split, from patching and capacity to token configuration and alert delivery.
An extra service to patch and monitor
The renderer is a second deployable with its own image, version and logs, so it needs the same patch cadence and monitoring as the Grafana server. Grafana ships minor releases every other month and patch releases at least monthly, so plan a standing change window for both services. Check that your monitoring alerts when the renderer stops responding, because a dead renderer usually fails quietly for report jobs and alert images.
Host cost for the resource floor
The renderer needs at least 16 GiB of memory and 4 CPU cores, which is far above the floor for a small Grafana server. That host is a recurring cost in cloud or data center capacity even when few reports run. Ask your platform team whether a dedicated node fits your capacity model, and compare it with the cost of a larger Grafana host that would carry the rendering load instead.
Network and token configuration overhead
Grafana and the renderer must reach each other over the network, and they share a secret set in the [rendering] section as renderer_token. With renderAuthJWT enabled by default in Grafana 13, a missing or mismatched token blocks every export. Plan firewall rules between the two hosts, store the token in your secrets tooling, and rotate it through the same change process you use for other service credentials.
Isolating heavy browser work
The renderer runs a headless browser to draw panels and dashboards, which consumes memory and CPU in bursts. Keeping that work off the Grafana server protects dashboard response times for interactive users while a large PDF or a batch of alert images is produced. The benefit depends on sizing: a renderer that is too small will still slow down, so test with your heaviest dashboards before you rely on the split.
Dependence on the renderer for alert images
When alert notifications include a panel image, a renderer outage means those notifications go out without the picture or fail, depending on how your contact points are set. Decide which alerts need an image and which can go out as text, since an operations team may need the graph in the message at 3 a.m. Confirm the fallback behavior in your Grafana version and test it by stopping the renderer on purpose in a non-production instance.
Renderer placement and reach
The renderer loads dashboards by requesting them from Grafana, so it must reach the Grafana address that users reach and it must sit where it can open the data sources the panels query. Placement in a restricted network, behind a proxy or in a separate subnet changes which URLs and certificates it uses. Document the path it takes and check it against your network policy before go-live.
How DeployOpen scopes and delivers renderer work
DeployOpen plans, implements, hardens and documents self-hosted Grafana inside your own infrastructure, including the Grafana Image Renderer service that produces PNG, PDF and CSV exports and alert images. The work runs in your cloud accounts, data centers or restricted networks, and the renderer stays under your control. Before any build starts, the scope is agreed in writing, so the renderer's sizing, deployment method, token configuration and verification steps are visible to you in advance, along with what you must supply, such as hosts, network routes and access to your Grafana instance.
The written scope usually covers the renderer's resource needs, which the Grafana image rendering docs put at a minimum of 16 GiB of memory and 4 CPU cores for the renderer itself, separate from the Grafana server. It also covers the Docker deployment, the shared [rendering] renderer_token that Grafana 13 requires when renderAuthJWT is enabled, and test renders of panels, dashboards and an alert notification image from each side of the connection. Confirm with DeployOpen whether your environment needs a supported load test, how many concurrent renders you expect, and who owns the token rotation process after handover.
After the first build, many teams move ongoing work to a retainer. DeployOpen offers retainers for upgrades and support, which suit renderer work because the renderer version has to stay compatible with each Grafana release you adopt, and token or resource changes need checking after every upgrade. Ask for the retainer terms, response expectations and upgrade testing approach in writing, and keep the handover documentation current so your own team can run the renderer if the engagement ends.

