{"id":30714060,"url":"https://github.com/farmdawgnation/metashot","last_synced_at":"2025-09-03T04:41:57.147Z","repository":{"id":303327450,"uuid":"1013470985","full_name":"farmdawgnation/metashot","owner":"farmdawgnation","description":"Generate PNG images from Metabase questions and upload to S3-compatible storage","archived":false,"fork":false,"pushed_at":"2025-08-09T02:55:08.000Z","size":760,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-01T14:00:01.494Z","etag":null,"topics":["metabase"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/farmdawgnation.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-04T00:52:59.000Z","updated_at":"2025-08-20T08:44:48.000Z","dependencies_parsed_at":"2025-07-07T03:37:52.057Z","dependency_job_id":"1a726073-6864-4d6d-96ab-0cf5ad938f0e","html_url":"https://github.com/farmdawgnation/metashot","commit_stats":null,"previous_names":["farmdawgnation/metashot"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/farmdawgnation/metashot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farmdawgnation%2Fmetashot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farmdawgnation%2Fmetashot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farmdawgnation%2Fmetashot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farmdawgnation%2Fmetashot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/farmdawgnation","download_url":"https://codeload.github.com/farmdawgnation/metashot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farmdawgnation%2Fmetashot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273392282,"owners_count":25097257,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["metabase"],"created_at":"2025-09-03T04:41:50.526Z","updated_at":"2025-09-03T04:41:57.128Z","avatar_url":"https://github.com/farmdawgnation.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Metashot\n\nMetabase is a fantastic business intelligence tool. However, one of the things that I've run into when implementing it\nat different places is the fact that there's no way to programatically extract a screen cap of a question created in\nmetabase.\n\nYou can get at the raw data, even metadata about the question. But Metabase _itself_ won't just generate a visualization\nfor you that you can throw into other tools. That changes today.\n\nMetashot is a TypeScript REST API service that generates PNG images from Metabase questions using Playwright. It automatically\ngenerates secure embed URLs using JWT tokens, captures screenshots of the visualizations, uploads them to S3-compatible \nstorage, and returns presigned download URLs. This makes it suitable to integrate with tools that need to ask for a \nfully realized image given a Metabase question ID.\n\n## Features\n\n- Generate PNG screenshots from Metabase questions using question IDs\n- Automatic JWT-based embed URL generation for secure access\n- Upload images to S3-compatible storage\n- Return presigned URLs with configurable expiration\n- Configurable viewport dimensions\n- Authentication via Bearer or Basic (password = AUTH_TOKEN)\n- Health check endpoint\n\n## Quick Start\n\n1. Install dependencies:\n```bash\nnpm install\n```\n\n2. Start local dependencies:\n```bash\ndocker-compose up -d\n```\n\n3. Copy environment configuration:\n```bash\ncp .env.example .env\n```\n\n4. Run the application:\n```bash\nnpm run dev\n```\n\n## API Endpoints\n\n### GET /\nReturns API information.\n\n**Response:**\n```json\n{\n  \"name\": \"Metashot API\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Generate PNG images from Metabase embed URLs\"\n}\n```\n\n### POST /api/screenshot\nGenerate a screenshot from a Metabase question.\n\n**Authentication:**\nIf `AUTH_TOKEN` is configured, requests must include either of the following headers:\n\n- Bearer token\n  ```\n  Authorization: Bearer \u003cAUTH_TOKEN\u003e\n  ```\n\n- Basic auth (password only; username is ignored)\n  ```\n  Authorization: Basic \u003cbase64(any-username:AUTH_TOKEN)\u003e\n  ```\n\nNotes:\n- Only the password portion of Basic auth is validated and must equal `AUTH_TOKEN`.\n- Health (`/api/health`) and metrics (`/metrics`) are always public.\n\n**Request Body:**\n```json\n{\n  \"questionId\": 123,\n  \"width\": 1920,\n  \"height\": 1080,\n  \"params\": {\n    \"parameter_name\": \"value\"\n  }\n}\n```\n\n**Parameters:**\n- `questionId` (required): The ID of the Metabase question to screenshot\n- `width` (optional): Viewport width in pixels (default: 1920)\n- `height` (optional): Viewport height in pixels (default: 1080)\n- `params` (optional): Object containing Metabase parameters to pass to the question\n\n**Response:**\n```json\n{\n  \"presignedUrl\": \"http://localhost:9000/metashot-images/screenshot-123456789-abc123.png?...\",\n  \"fileName\": \"screenshot-123456789-abc123.png\",\n  \"expiresAt\": \"2024-01-01T12:00:00.000Z\"\n}\n```\n\n### GET /api/health\nHealth check endpoint (no authentication required).\n\n**Response:**\n```json\n{\n  \"status\": \"healthy\",\n  \"timestamp\": \"2024-01-01T12:00:00.000Z\"\n}\n```\n\n### GET /metrics\nPrometheus metrics endpoint for monitoring (no authentication required).\n\n**Response:**\nPrometheus metrics in text format, including:\n- HTTP request metrics (duration, count, status codes)\n- Application-specific metrics\n- System metrics\n\n## Development\n\n- `npm run dev` - Start development server\n- `npm run build` - Build for production\n- `npm run test` - Run tests\n- `npm run lint` - Run linting\n- `npm run typecheck` - Run TypeScript type checking\n\n## Deployment\n\n### Docker\n\nA Docker container is available for easy deployment:\n\n```bash\n# Build the Docker image\ndocker build -t metashot .\n\n# Run the container\ndocker run -d -p 8080:8080 --name metashot metashot\n```\n\n### Kubernetes with Helm\n\nA Helm chart is provided for Kubernetes deployment with comprehensive configuration options:\n\n```bash\n# Install with basic configuration\nhelm install metashot helm/metashot \\\n  --set env.METABASE_SITE_URL=https://metabase.example.com \\\n  --set env.S3_BUCKET=my-screenshots-bucket\n\n# Install with external secrets using envFrom\nhelm install metashot helm/metashot \\\n  --set env.METABASE_SITE_URL=https://metabase.example.com \\\n  --set env.S3_BUCKET=my-screenshots-bucket \\\n  --set envFrom[0].secretRef.name=metashot-secrets\n```\n\n#### Helm Chart Features\n\nThe Helm chart supports:\n- Environment variables from external sources (secrets, configmaps) via `envFrom`\n- Ingress configuration with TLS support\n- Horizontal Pod Autoscaling\n- Custom resource limits and requests\n- Extra Kubernetes objects deployment\n- Configurable health checks\n- Security contexts and pod security policies\n- Volume mounts and persistent storage\n\n#### Chart Documentation\n\nThe Helm chart includes comprehensive documentation with:\n- Complete values table with descriptions\n- Installation and configuration examples\n- Security best practices\n- Upgrade and uninstallation instructions\n\nSee the [Helm Chart README](./helm/metashot/README.md) for detailed configuration options and examples.\n\n#### Quick Start with Helm\n\n1. **Create a secret for sensitive values:**\n```bash\nkubectl create secret generic metashot-secrets \\\n  --from-literal=S3_SECRET_ACCESS_KEY=your-s3-secret-key \\\n  --from-literal=METABASE_SECRET_KEY=your-metabase-secret-key \\\n  --from-literal=AUTH_TOKEN=your-auth-token\n```\n\n2. **Install the chart:**\n```bash\nhelm install metashot ./helm/metashot \\\n  --set env.METABASE_SITE_URL=https://metabase.example.com \\\n  --set env.S3_BUCKET=my-screenshots-bucket \\\n  --set env.S3_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE \\\n  --set envFrom[0].secretRef.name=metashot-secrets\n```\n\n3. **Enable ingress for external access:**\n```bash\nhelm upgrade metashot ./helm/metashot \\\n  --set ingress.enabled=true \\\n  --set ingress.hosts[0].host=metashot.example.com \\\n  --set ingress.hosts[0].paths[0].path=/ \\\n  --set ingress.hosts[0].paths[0].pathType=Prefix\n```\n\n## Docker Services\n\nThe `docker-compose.yml` provides:\n- **MinIO** (S3-compatible storage) on port 9000\n- **Metabase** for testing embed URLs on port 3000\n\n## How It Works\n\nMetashot integrates directly with Metabase's embedding feature:\n\n1. **Prerequisites**: The Metabase question must be shared via public embedding (in Metabase, go to the question \u003e sharing icon \u003e \"Embed this question in an application\")\n2. You provide a Metabase question ID\n3. Metashot generates a secure JWT token using your `METABASE_SECRET_KEY`\n4. It creates an embed URL for the question with appropriate parameters\n5. Playwright navigates to the embed URL and waits for the visualization to load\n6. A full-page screenshot is captured in PNG format\n7. The image is uploaded to S3-compatible storage\n8. A presigned URL is returned for temporary access to the image\n\nThe generated embed URLs include:\n- JWT token with configurable expiry (default: 10 minutes)\n- Bordered and titled display (configurable in future versions)\n- Support for passing additional parameters to Metabase questions\n\n## Configuration\n\nEnvironment variables:\n- `PORT` - Server port (default: 8080)\n- `NODE_ENV` - Environment (development/production)\n- `AUTH_TOKEN` - Token required for API authentication (optional). When set, clients may authenticate with either:\n  - `Authorization: Bearer \u003cAUTH_TOKEN\u003e` or\n  - `Authorization: Basic \u003cbase64(any:AUTH_TOKEN)\u003e` (only the password is checked)\n- `METABASE_SITE_URL` - Base URL of your Metabase instance (e.g., https://metabase.example.com)\n- `METABASE_SECRET_KEY` - Secret key for generating Metabase embed tokens (found in Metabase Admin \u003e Settings \u003e Embedding)\n- `S3_ENDPOINT` - S3 endpoint URL (optional, defaults to AWS S3; set for MinIO or other S3-compatible services)\n- `S3_ACCESS_KEY_ID` - S3 access key\n- `S3_SECRET_ACCESS_KEY` - S3 secret key\n- `S3_BUCKET` - S3 bucket name\n- `S3_REGION` - S3 region\n- `PRESIGNED_URL_EXPIRY` - Presigned URL expiry in seconds (default: 3600, 1 hour)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffarmdawgnation%2Fmetashot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffarmdawgnation%2Fmetashot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffarmdawgnation%2Fmetashot/lists"}