{"_id":"@brahimtimezghine/screenshot-api","name":"@brahimtimezghine/screenshot-api","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@brahimtimezghine/screenshot-api","version":"1.0.0","description":"Ultra-fast, memory-efficient Node.js screenshot service — 200MB RAM vs 8GB for vanilla Puppeteer","main":"src/index.js","type":"module","engines":{"node":">=18.0.0","npm":">=9.0.0"},"scripts":{"start":"node src/index.js","start:gc":"node --expose-gc src/index.js","dev":"nodemon --experimental-vm-modules src/index.js","test":"node --experimental-vm-modules node_modules/.bin/jest --coverage","test:unit":"node --experimental-vm-modules node_modules/.bin/jest tests/unit --coverage","test:integration":"node --experimental-vm-modules node_modules/.bin/jest tests/integration","test:watch":"node --experimental-vm-modules node_modules/.bin/jest --watch","lint":"eslint src/ --fix --ext .js","lint:check":"eslint src/ --ext .js","format":"prettier --write \"src/**/*.js\" \"tests/**/*.js\"","migrate":"node scripts/migrate.js","benchmark":"node scripts/benchmark.js","docker:build":"docker build -t screenshot-api:latest .","docker:run":"docker-compose up -d","docker:stop":"docker-compose down","docker:logs":"docker-compose logs -f"},"keywords":["screenshot","puppeteer","api","nodejs","web-automation","fast","lightweight","memory-efficient","seo","monitoring","headless-browser"],"author":{"name":"screenshot-api contributors"},"license":"MIT","dependencies":{"express":"^4.18.2","puppeteer":"^21.5.0","sharp":"^0.32.6","redis":"^4.6.10","mongoose":"^7.6.3","dotenv":"^16.3.1","joi":"^17.11.0","winston":"^3.11.0","winston-daily-rotate-file":"^4.7.1","compression":"^1.7.4","cors":"^2.8.5","helmet":"^7.1.0","express-rate-limit":"^7.1.5","jsonwebtoken":"^9.0.2","bcryptjs":"^2.4.3","axios":"^1.6.2","uuid":"^9.0.1","p-queue":"^8.0.1","p-retry":"^6.2.0","ms":"^2.1.3"},"devDependencies":{"nodemon":"^3.0.2","jest":"^29.7.0","supertest":"^6.3.3","eslint":"^8.54.0","prettier":"^3.1.0","@jest/globals":"^29.7.0"},"jest":{"testEnvironment":"node","transform":{},"extensionsToTreatAsEsm":[".js"],"moduleNameMapper":{"^(\\.{1,2}/.*)\\.js$":"$1"},"coverageDirectory":"coverage","collectCoverageFrom":["src/**/*.js","!src/index.js"]},"gitHead":"b8ea93111622a2c29aedd322e02d994698f0305b","_id":"@brahimtimezghine/screenshot-api@1.0.0","_nodeVersion":"24.15.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-R6zjTevra0e87OK3VvZQcJI6EQFDL72SZHSxnWL7+WXQXx50qQifCs6QGxmu/odkjc7mG6q+3sHhqKCYRyhe2g==","shasum":"aba386640241a312f1c4d83454d7900c39247b7b","tarball":"https://registry.npmjs.org/@brahimtimezghine/screenshot-api/-/screenshot-api-1.0.0.tgz","fileCount":44,"unpackedSize":144620,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAtIZUS0HKBllERTLxVkZwP4AIyrS0744bRbehilnb5TAiAhsAVXMJPTqa/zh67hiW0w/L12pqhO60G3I0DObMHOMg=="}]},"_npmUser":{"name":"brahimtimezghine","email":"brahimtimezghine.mail@gmail.com"},"directories":{},"maintainers":[{"name":"brahimtimezghine","email":"brahimtimezghine.mail@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/screenshot-api_1.0.0_1781619325608_0.1164661377493934"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-16T14:15:25.467Z","1.0.0":"2026-06-16T14:15:25.760Z","modified":"2026-06-16T14:15:25.985Z"},"maintainers":[{"name":"brahimtimezghine","email":"brahimtimezghine.mail@gmail.com"}],"description":"Ultra-fast, memory-efficient Node.js screenshot service — 200MB RAM vs 8GB for vanilla Puppeteer","keywords":["screenshot","puppeteer","api","nodejs","web-automation","fast","lightweight","memory-efficient","seo","monitoring","headless-browser"],"author":{"name":"screenshot-api contributors"},"license":"MIT","readme":"# screenshot-api\n\n**Ultra-fast, memory-efficient Node.js screenshot service**  \n200 MB RAM usage · 1–2 s per capture · 500+ concurrent requests · 99.5 %+ reliability\n\n---\n\n## Why screenshot-api?\n\n| Metric | Puppeteer (vanilla) | **screenshot-api** |\n|--------|--------------------|--------------------|\n| RAM at scale | 8–10 GB | **200–300 MB** |\n| Latency (p50) | 3–5 s | **1–2 s** |\n| Concurrent reqs | 10–20 | **500+** |\n| Error rate | 5–10 % | **< 0.5 %** |\n| Monthly cost | $500+ | **$14 (Pro)** |\n\nKey techniques:\n- **Browser pool** with health-checks & auto-recycling (no memory leaks)\n- **Two-tier cache** (in-process LRU + Redis) — repeat URLs return instantly\n- **Resource interception** blocks fonts/media during capture\n- **MemoryOptimizer** polls heap every 10 s; triggers GC at 85 %\n- **Smart retry** via p-retry with exponential back-off\n\n---\n\n## Quick Start\n\n```bash\n# Docker (recommended)\ncp .env.example .env      # set JWT_SECRET\ndocker-compose up -d\ncurl http://localhost:3000/health\n\n# Manual\nnpm install\ncp .env.example .env\nnpm run dev\n```\n\n---\n\n## API at a Glance\n\n### 1. Register & Login\n\n```bash\n# Register\ncurl -X POST http://localhost:3000/api/v1/auth/register \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"you@example.com\",\"password\":\"SecurePass1\",\"name\":\"You\"}'\n\n# Login\nTOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"you@example.com\",\"password\":\"SecurePass1\"}' | jq -r .token)\n```\n\n### 2. Capture a screenshot\n\n```bash\n# → raw PNG bytes\ncurl -X POST http://localhost:3000/api/v1/screenshot \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\":\"https://example.com\",\"format\":\"png\"}' \\\n  --output screenshot.png\n\n# → JSON with base64 data\ncurl -X POST \"http://localhost:3000/api/v1/screenshot?json=1\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\":\"https://example.com\",\"full\":true,\"mobile\":true}'\n```\n\n### 3. Batch capture\n\n```bash\ncurl -X POST http://localhost:3000/api/v1/screenshot/batch \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"urls\":[\"https://example.com\",\"https://github.com\"],\"concurrency\":2}'\n```\n\n### 4. Check usage\n\n```bash\ncurl http://localhost:3000/api/v1/usage \\\n  -H \"Authorization: Bearer $TOKEN\"\n```\n\n---\n\n## Capture Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `url` | string | **required** | Target URL (http/https) |\n| `full` | boolean | false | Full-page capture |\n| `mobile` | boolean | false | Mobile viewport (iPhone 14) |\n| `device` | string | null | `desktop` `laptop` `tablet` `mobile` `mobile-landscape` |\n| `width` | number | 1920 | Viewport width (320–3840) |\n| `height` | number | 1080 | Viewport height (240–2160) |\n| `format` | string | `png` | `png` `jpeg` `webp` |\n| `quality` | number | 90 | JPEG/WebP quality (1–100) |\n| `delay` | number | 0 | Extra wait after load (seconds) |\n| `waitUntil` | string | `networkidle2` | Puppeteer wait strategy |\n| `waitForSelector` | string | null | CSS selector to wait for |\n| `timeout` | number | 30000 | Navigation timeout (ms) |\n| `compress` | boolean | false | Resize to fit 1920×1080 |\n| `useCache` | boolean | true | Enable L1/L2 cache |\n| `clip` | object | null | `{x,y,width,height}` crop |\n\n---\n\n## Pricing\n\n| Tier | Quota | Price |\n|------|-------|-------|\n| Free | 1,000 screenshots/month | $0 |\n| Pro  | 100,000 screenshots/month | $14/month |\n| Enterprise | Unlimited | Custom |\n\n---\n\n## Project Structure\n\n```\nscreenshot-api/\n├── src/\n│   ├── core/\n│   │   ├── BrowserManager.js     # Pool of Puppeteer instances\n│   │   ├── PoolManager.js        # Generic job queue (p-queue + p-retry)\n│   │   ├── ScreenshotEngine.js   # Main capture façade\n│   │   └── MemoryOptimizer.js    # Heap monitoring + GC\n│   ├── rendering/\n│   │   ├── Renderer.js           # Page navigation + screenshot\n│   │   ├── CacheLayer.js         # L1 LRU + L2 Redis\n│   │   └── ViewportHandler.js    # Viewport/UA resolution\n│   ├── api/\n│   │   ├── ApiServer.js          # Express app factory\n│   │   ├── RouterV1.js           # All v1 routes\n│   │   ├── controllers/          # screenshotController, authController\n│   │   └── middleware/           # auth, rateLimiter, validate, errorHandler\n│   ├── database/\n│   │   ├── db.js                 # Mongoose connection helper\n│   │   └── models/               # User, Subscription, UsageLog\n│   ├── utils/\n│   │   ├── logger.js             # Winston (console + rotating files)\n│   │   ├── urlValidator.js       # URL normalise + security checks\n│   │   ├── imageProcessor.js     # Sharp post-processing helpers\n│   │   └── config.js             # Centralised env-based config\n│   └── index.js                  # Bootstrap entry-point\n├── tests/\n│   ├── unit/                     # core.test.js, utils.test.js\n│   └── integration/              # api.test.js (supertest + mocked engine)\n├── scripts/\n│   ├── migrate.js                # DB migrations + optional admin seed\n│   └── benchmark.js              # Load-test against live instance\n├── config/\n│   ├── development.json\n│   ├── production.json\n│   └── test.json\n├── docs/\n│   ├── API.md                    # Full API reference\n│   ├── ARCHITECTURE.md           # System design\n│   ├── INSTALLATION.md           # Setup guide\n│   └── EXAMPLES.md               # Code examples\n├── Dockerfile                    # Multi-stage production image\n├── docker-compose.yml            # App + MongoDB + Redis\n├── .env.example                  # All environment variables\n└── package.json\n```\n\n---\n\n## Configuration\n\nCopy `.env.example` to `.env`.  \nEssential variables:\n\n```env\nPORT=3000\nMONGO_URL=mongodb://localhost:27017/screenshot_api\nREDIS_URL=redis://localhost:6379\nJWT_SECRET=<64-char-random-string>\nBROWSER_WORKERS=4\nNODE_ENV=production\n```\n\nFull list: see [`.env.example`](.env.example)\n\n---\n\n## Scripts\n\n```bash\nnpm start               # Production start\nnpm run dev             # Development with nodemon\nnpm test                # Jest tests with coverage\nnpm run migrate         # Create DB collections & indexes\nnpm run benchmark       # Load test (set BENCH_TOKEN first)\nnpm run docker:build    # Build Docker image\nnpm run docker:run      # Start full stack (docker-compose)\n```\n\n---\n\n## Health & Monitoring\n\n```bash\n# Health endpoint (no auth)\ncurl http://localhost:3000/health\n\n# System status (auth required)\ncurl http://localhost:3000/api/v1/status \\\n  -H \"Authorization: Bearer $TOKEN\"\n```\n\nResponse includes browser-pool, cache hit rate, and memory telemetry.\n\n---\n\n## Use Cases\n\n| Use Case | Typical Volume |\n|----------|---------------|\n| SEO monitoring | 5,000–50,000/day |\n| Competitive intelligence | 1,000–10,000/day |\n| Visual regression testing | 100–1,000/run |\n| Report generation | 500–5,000/day |\n| Design verification | 100–500/day |\n\n---\n\n## License\n\nMIT © screenshot-api contributors\n\n---\n\n## Performance Architecture\n\n```\nRequest → Express → Auth → Validate → ScreenshotEngine\n                                            │\n                              ┌─────────────┴──────────────┐\n                              │                            │\n                         CacheLayer (hit)          BrowserManager (miss)\n                              │                            │\n                         return <1ms              Puppeteer page\n                                                   Renderer.render()\n                                                   Sharp post-process\n                                                   CacheLayer.set()\n                                                   return ~1.5s\n```\n\nTwo replicas behind a load-balancer share Redis → effective cache hit rate approaches 60–80 % for common URLs.\n","readmeFilename":"README.md","_rev":"1-1dd03b18094a4cbc77b3b6762a0ba8f4"}