{"id":8206,"library":"grafana-client","title":"Grafana Client","description":"A client library for accessing the Grafana HTTP API, written in Python. It covers most available Grafana HTTP API endpoints and supports Grafana 5.x-9.x, with ongoing compatibility for newer versions, including Grafana 11. The library is actively maintained with a regular release cadence, supporting HTTP Basic authentication and token-based authentication.","status":"active","version":"5.0.2","language":"en","source_language":"en","source_url":"https://github.com/grafana-toolbox/grafana-client","tags":["grafana","http","api","grafana-client","grafana-api","http-client","grafana-utils","grafana-automation","grafana-toolbox"],"install":[{"cmd":"pip install --upgrade grafana-client","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"symbol":"GrafanaApi","correct":"from grafana_client import GrafanaApi"},{"symbol":"AsyncGrafanaApi","correct":"from grafana_client import AsyncGrafanaApi"},{"note":"The 'grafana_api' package is an older, unmaintained library. 'grafana-client' is its spiritual successor. Ensure you are importing from 'grafana_client'.","wrong":"from grafana_api.grafana_api import GrafanaAPI","symbol":"GrafanaAPI","correct":"from grafana_client import GrafanaApi"}],"quickstart":{"code":"import os\nfrom grafana_client import GrafanaApi\n\nGRAFANA_URL = os.environ.get('GRAFANA_URL', 'http://localhost:3000')\nGRAFANA_TOKEN = os.environ.get('GRAFANA_TOKEN', 'eyJrIjoiV1N...') # Or 'admin:admin' for basic auth\n\n# For API token authentication\n# grafana = GrafanaApi.from_url(f\"{GRAFANA_URL}\", token=GRAFANA_TOKEN)\n\n# For basic authentication (e.g., admin user)\nusername, password = GRAFANA_TOKEN.split(':', 1) if ':' in GRAFANA_TOKEN else ('', '')\nif not username or not password:\n    print(\"Warning: GRAFANA_TOKEN env var not set correctly for basic auth (e.g., 'admin:admin').\")\n    print(\"Trying with API token instead.\")\n    grafana = GrafanaApi.from_url(GRAFANA_URL, token=GRAFANA_TOKEN)\nelse:\n    grafana = GrafanaApi.from_url(GRAFANA_URL, basic_auth=(username, password))\n\ntry:\n    # Get Grafana's current version (requires authentication since 5.0.0)\n    version_info = grafana.version()\n    print(f\"Connected to Grafana version: {version_info.get('version')}\")\n\n    # Example: List all dashboards\n    dashboards = grafana.search.search_dashboards()\n    print(f\"Found {len(dashboards)} dashboards.\")\n    if dashboards:\n        print(f\"First dashboard title: {dashboards[0].get('title')}\")\n\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")\n    print(\"Ensure GRAFANA_URL and GRAFANA_TOKEN are correctly set.\")\n","lang":"python","description":"This quickstart demonstrates how to connect to a Grafana instance using either an API token or HTTP Basic Authentication. It then retrieves the Grafana version and lists existing dashboards. Ensure `GRAFANA_URL` and `GRAFANA_TOKEN` environment variables are set. For API token, `GRAFANA_TOKEN` should be the token itself. For basic auth, it should be in `username:password` format."},"warnings":[{"fix":"Ensure all GrafanaApi initializations include authentication credentials (e.g., `token` or `basic_auth`). If upgrading from a pre-5.0.0 version and calls were unauthenticated, they will now fail.","message":"Version 5.0.0 introduced a breaking change: authentication is now *obligatory* for all API calls, as the library fetches the Grafana version from `/api/frontend/settings` instead of `/api/health`. The `/api/health` endpoint previously allowed unauthenticated access. Additionally, the 'database' status is no longer represented in the response.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Update exception handling blocks to catch `GrafanaTimeoutError` instead of `requests.exceptions.Timeout`. If using Python 3.6, upgrade to Python 3.7 or newer.","message":"Version 4.0.0 changed the underlying HTTP backend from `requests` to `niquests`. This primarily affects error handling, as `requests.exceptions.Timeout` exceptions are no longer propagated. Instead, `GrafanaTimeoutError` is used. Python 3.6 support was also dropped.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Always generate Grafana API keys with the least privileged role necessary for your script's operations (e.g., Editor for dashboard management, Admin for user management). Double-check Grafana logs for permission-related errors if an API call seems to succeed but yields unexpected results.","message":"Insufficient Grafana API Key Permissions: A common issue is providing an API key with inadequate permissions for the desired operations (e.g., a Viewer key trying to create dashboards). While the API might return a 200 OK, the operation may silently fail or return an empty result.","severity":"gotcha","affected_versions":"All"},{"fix":"To ensure operations target a specific organization, use an API token (which is tied to one org) or explicitly switch the user's organization context using `GrafanaApi.user.switch_actual_user_organisation` after authentication. Alternatively, bind the `GrafanaApi` instance to a specific organization using `organization_id` parameter, which sends the `X-Grafana-Org-Id` header.","message":"Grafana Organization Context with HTTP Basic Authentication: When using HTTP Basic Authentication, requests are made within the authenticated user's current organization context. This might lead to unexpected behavior if the user is part of multiple organizations and the desired organization is not active. API tokens are typically bound to a single organization.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Verify that the `GRAFANA_URL` is correct and accessible from the machine running the script. Check network connectivity, firewall rules, and proxy settings. Ensure the Grafana instance is running and listening on the specified port.","cause":"This error typically indicates a network connectivity issue, an incorrect Grafana URL, or a firewall blocking access to the Grafana instance from where the Python script is run. It's not usually an API-level error.","error":"Max retries exceeded with url: /api/datasources"},{"fix":"Always inspect the `response.text` or content even on 200 OK status for Grafana-specific error messages. In this particular case, contact Grafana Cloud support or check your Grafana instance's billing and service status.","cause":"While the HTTP status code might be 200 OK, the actual response body from Grafana indicates an internal server-side error, often related to Grafana Cloud billing or a similar service-specific issue that prevents the operation from completing.","error":"An unexpected error happened DetailsTypeError: Cannot read properties of undefined (reading 'usageBilling')"},{"fix":"Remove direct `import requests` if it's only for `grafana-client` operations. Update exception handling for timeouts to catch `grafana_client.errors.GrafanaTimeoutError` instead of `requests.exceptions.Timeout`. If you need `requests` for other purposes, import it explicitly.","cause":"Since version 4.0.0, `grafana-client` no longer directly uses the `requests` library for its HTTP backend. Code that relies on importing `requests` or catching `requests.exceptions.Timeout` will fail.","error":"NameError: name 'requests' is not defined (or similar import error for 'requests.exceptions.Timeout')"}]}