Metashot
Metabase is a fantastic business intelligence tool. However, one of the things that I've run into when implementing it at different places is the fact that there's no way to programatically extract a screen cap of a question created in metabase.
You can get at the raw data, even metadata about the question. But Metabase itself won't just generate a visualization for you that you can throw into other tools. That changes today.
Metashot is a TypeScript REST API service that generates PNG images from Metabase questions using Playwright. It automatically generates secure embed URLs using JWT tokens, captures screenshots of the visualizations, uploads them to S3-compatible storage, and returns presigned download URLs. This makes it suitable to integrate with tools that need to ask for a fully realized image given a Metabase question ID.
Features
- Generate PNG screenshots from Metabase questions using question IDs
- Automatic JWT-based embed URL generation for secure access
- Upload images to S3-compatible storage
- Return presigned URLs with configurable expiration
- Configurable viewport dimensions
- Authentication via Bearer or Basic (password = AUTH_TOKEN)
- Health check endpoint
Quick Start
- Install dependencies:
- Start local dependencies:
- Copy environment configuration:
- Run the application:
API Endpoints
GET /
Returns API information.
Response:
{
"name": "Metashot API",
"version": "1.0.0",
"description": "Generate PNG images from Metabase embed URLs"
}POST /api/screenshot
Generate a screenshot from a Metabase question.
Authentication:
If AUTH_TOKEN is configured, requests must include either of the following headers:
-
Bearer token
Authorization: Bearer <AUTH_TOKEN> -
Basic auth (password only; username is ignored)
Authorization: Basic <base64(any-username:AUTH_TOKEN)>
Notes:
- Only the password portion of Basic auth is validated and must equal
AUTH_TOKEN. - Health (
/api/health) and metrics (/metrics) are always public.
Request Body:
{
"questionId": 123,
"width": 1920,
"height": 1080,
"params": {
"parameter_name": "value"
}
}Parameters:
questionId(required): The ID of the Metabase question to screenshotwidth(optional): Viewport width in pixels (default: 1920)height(optional): Viewport height in pixels (default: 1080)params(optional): Object containing Metabase parameters to pass to the question
Response:
{
"presignedUrl": "http://localhost:9000/metashot-images/screenshot-123456789-abc123.png?...",
"fileName": "screenshot-123456789-abc123.png",
"expiresAt": "2024-01-01T12:00:00.000Z"
}GET /api/health
Health check endpoint (no authentication required).
Response:
{
"status": "healthy",
"timestamp": "2024-01-01T12:00:00.000Z"
}GET /metrics
Prometheus metrics endpoint for monitoring (no authentication required).
Response: Prometheus metrics in text format, including:
- HTTP request metrics (duration, count, status codes)
- Application-specific metrics
- System metrics
Development
npm run dev- Start development servernpm run build- Build for productionnpm run test- Run testsnpm run lint- Run lintingnpm run typecheck- Run TypeScript type checking
Deployment
Docker
A Docker container is available for easy deployment:
# Build the Docker image docker build -t metashot . # Run the container docker run -d -p 8080:8080 --name metashot metashot
Kubernetes with Helm
A Helm chart is provided for Kubernetes deployment with comprehensive configuration options:
# Install with basic configuration helm install metashot helm/metashot \ --set env.METABASE_SITE_URL=https://metabase.example.com \ --set env.S3_BUCKET=my-screenshots-bucket # Install with external secrets using envFrom helm install metashot helm/metashot \ --set env.METABASE_SITE_URL=https://metabase.example.com \ --set env.S3_BUCKET=my-screenshots-bucket \ --set envFrom[0].secretRef.name=metashot-secrets
Helm Chart Features
The Helm chart supports:
- Environment variables from external sources (secrets, configmaps) via
envFrom - Ingress configuration with TLS support
- Horizontal Pod Autoscaling
- Custom resource limits and requests
- Extra Kubernetes objects deployment
- Configurable health checks
- Security contexts and pod security policies
- Volume mounts and persistent storage
Chart Documentation
The Helm chart includes comprehensive documentation with:
- Complete values table with descriptions
- Installation and configuration examples
- Security best practices
- Upgrade and uninstallation instructions
See the Helm Chart README for detailed configuration options and examples.
Quick Start with Helm
- Create a secret for sensitive values:
kubectl create secret generic metashot-secrets \ --from-literal=S3_SECRET_ACCESS_KEY=your-s3-secret-key \ --from-literal=METABASE_SECRET_KEY=your-metabase-secret-key \ --from-literal=AUTH_TOKEN=your-auth-token
- Install the chart:
helm install metashot ./helm/metashot \ --set env.METABASE_SITE_URL=https://metabase.example.com \ --set env.S3_BUCKET=my-screenshots-bucket \ --set env.S3_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE \ --set envFrom[0].secretRef.name=metashot-secrets
- Enable ingress for external access:
helm upgrade metashot ./helm/metashot \ --set ingress.enabled=true \ --set ingress.hosts[0].host=metashot.example.com \ --set ingress.hosts[0].paths[0].path=/ \ --set ingress.hosts[0].paths[0].pathType=Prefix
Docker Services
The docker-compose.yml provides:
- MinIO (S3-compatible storage) on port 9000
- Metabase for testing embed URLs on port 3000
How It Works
Metashot integrates directly with Metabase's embedding feature:
- Prerequisites: The Metabase question must be shared via public embedding (in Metabase, go to the question > sharing icon > "Embed this question in an application")
- You provide a Metabase question ID
- Metashot generates a secure JWT token using your
METABASE_SECRET_KEY - It creates an embed URL for the question with appropriate parameters
- Playwright navigates to the embed URL and waits for the visualization to load
- A full-page screenshot is captured in PNG format
- The image is uploaded to S3-compatible storage
- A presigned URL is returned for temporary access to the image
The generated embed URLs include:
- JWT token with configurable expiry (default: 10 minutes)
- Bordered and titled display (configurable in future versions)
- Support for passing additional parameters to Metabase questions
Configuration
Environment variables:
PORT- Server port (default: 8080)NODE_ENV- Environment (development/production)AUTH_TOKEN- Token required for API authentication (optional). When set, clients may authenticate with either:Authorization: Bearer <AUTH_TOKEN>orAuthorization: Basic <base64(any:AUTH_TOKEN)>(only the password is checked)
METABASE_SITE_URL- Base URL of your Metabase instance (e.g., https://metabase.example.com)METABASE_SECRET_KEY- Secret key for generating Metabase embed tokens (found in Metabase Admin > Settings > Embedding)S3_ENDPOINT- S3 endpoint URL (optional, defaults to AWS S3; set for MinIO or other S3-compatible services)S3_ACCESS_KEY_ID- S3 access keyS3_SECRET_ACCESS_KEY- S3 secret keyS3_BUCKET- S3 bucket nameS3_REGION- S3 regionPRESIGNED_URL_EXPIRY- Presigned URL expiry in seconds (default: 3600, 1 hour)