A high-performance image proxy and web services toolkit built with modern TypeScript. Lens provides a comprehensive suite of web utilities including image processing, screenshot capture, font serving, and more.
- πΌοΈ Image Proxy: IPX-powered image processing with resize, format conversion, optimization
- πΈ Screenshot Capture: Fast website screenshot service with resource optimization
- π Reader: Article content extraction (HTML/Markdown) with Readability
π °οΈ Font Service: Google Fonts compatible API with multiple providers- π¨ Open Graph Images: Dynamic OG image generation
- π― Favicon Extraction: Smart favicon extraction from websites
- π€ Gravatar Proxy: Cached Gravatar avatar proxy with email or hash input
- π€ MCP Server: Model Context Protocol server exposing all services as tools via JSON-RPC 2.0
- β‘ Redis Caching: Redis-powered caching with 24-hour intelligent caching
- π Resource Optimization: Optimized page loading with blocked unnecessary resources
- π‘οΈ Rate Limiting: Rate limiting for expensive operations
- π Graceful Degradation: Automatic fallbacks for missing services
- Node.js 22+
- pnpm 10+ (recommended) or npm
# Clone the repository
git clone https://github.com/bysages/lens.git
cd lens
# Install dependencies
pnpm install
# Copy environment configuration
cp .env.example .env# Start development server
pnpm dev
# Build for production
pnpm build
# Preview production build
pnpm previewThe server will start on http://localhost:3000 by default.
All configurations are optional and will gracefully degrade:
# Image proxy security
ALLOWED_DOMAINS=example.com,cdn.example.com
# Caching (significantly improves performance)
REDIS_URL=redis://localhost:6379See .env.example for all available options.
All cached responses include X-Cache headers (HIT/MISS) and ETag headers for conditional 304 responses.
Transform and optimize images on-the-fly:
GET /img/{modifiers}/{image_url}
Examples:
# Resize to 300px width, convert to WebP
https://api.bysages.com/img/w_300,f_webp/https://example.com/image.jpg
# Create 200x200 square thumbnail
https://api.bysages.com/img/s_200x200,q_80/https://example.com/image.png
# Smart crop with high quality
https://api.bysages.com/img/w_400,h_300,c_fill,q_95/https://example.com/photo.jpgSupported Modifiers:
w_XXX- Widthh_XXX- Heights_XXXxYYY- Size (width x height)f_FORMAT- Format (webp, jpg, png, avif)q_XXX- Quality (1-100)c_MODE- Crop mode (fill, fit, pad)
Performance Features:
- Redis caching for optimal performance
- Automatic format optimization and compression
Capture website screenshots with Playwright-aligned options:
GET /screenshot?url={website_url}&options
Examples:
# Basic screenshot
https://api.bysages.com/screenshot?url=https://example.com
# JPEG with custom quality
https://api.bysages.com/screenshot?url=https://example.com&type=jpeg&quality=80
# Mobile screenshot with custom viewport
https://api.bysages.com/screenshot?url=https://example.com&width=375&height=667&mobile=true
# Full page capture
https://api.bysages.com/screenshot?url=https://example.com&fullPage=true
# Clip region (x,y,width,height)
https://api.bysages.com/screenshot?url=https://example.com&clip=0,0,400,300
# Transparent background
https://api.bysages.com/screenshot?url=https://example.com&omitBackground=true
# Disable animations for clean capture
https://api.bysages.com/screenshot?url=https://example.com&animations=disabled
# Custom CSS scale
https://api.bysages.com/screenshot?url=https://example.com&scale=css
# Inject custom stylesheet
https://api.bysages.com/screenshot?url=https://example.com&style=body{background:red}Parameters:
| Parameter | Description | Default |
|---|---|---|
url |
Website URL (required) | - |
width |
Viewport width (100-2560) | 1280 |
height |
Viewport height (100-1440) | 720 |
type |
Output format (png, jpeg) |
png |
quality |
Image quality, 1-100 (jpeg only) | - |
fullPage |
Capture full scrollable page (true/false) |
false |
clip |
Clip region as x,y,width,height |
- |
omitBackground |
Hide default white background (true/false, png only) |
false |
scale |
Screenshot scale (css for CSS pixels, device for device pixels) |
device |
animations |
Animation handling (disabled or allow) |
allow |
caret |
Text caret (hide or initial) |
hide |
style |
Custom CSS stylesheet to apply | - |
timeout |
Navigation timeout in ms (1000-30000) | 10000 |
mobile |
Mobile viewport (true/false) |
false |
darkMode |
Dark mode (true/false) |
false |
waitUntil |
Navigation wait condition (load, domcontentloaded, networkidle) |
domcontentloaded |
delay |
Additional delay in ms after page load (0-10000) | - |
Performance Notes:
- Screenshots are cached for 1 day with rate limiting
- Identical requests return cached results with sub-second response times
- Resource optimization (blocking fonts, media, websockets) speeds up screenshot generation by 60-80%
Generate dynamic OG images:
GET /og?title={title}&description={description}
Examples:
# Basic OG image
https://api.bysages.com/og?title=Welcome&description=Get%20started%20with%20Lens
# Custom styling
https://api.bysages.com/og?title=Hello%20World&theme=dark&fontSize=72&width=1200&height=630Caching:
- Generated OG images are cached for 24 hours
- Identical requests with same parameters return cached results instantly
Extract rendered HTML or Markdown content from any URL:
GET /reader?url={website_url}&options
Examples:
# Extract rendered HTML
https://api.bysages.com/reader?url=https://github.com/bysages/lens
# Convert to Markdown
https://api.bysages.com/reader?url=https://github.com/bysages/lens&format=markdown
# Wait for full page load
https://api.bysages.com/reader?url=https://github.com/bysages/lens&waitUntil=loadParameters:
| Parameter | Description | Default |
|---|---|---|
url |
Website URL (required) | - |
format |
Output format (html, markdown) |
html |
waitUntil |
Navigation wait condition (load, domcontentloaded, networkidle) |
domcontentloaded |
delay |
Additional delay in ms after page load (0-10000) | - |
timeout |
Navigation timeout in ms (1000-30000) | 10000 |
Extract high-quality favicons:
GET /favicon?url={website_url}&size={size}
Examples:
# Extract favicon
https://api.bysages.com/favicon?url=github.com
# Custom size
https://api.bysages.com/favicon?url=github.com&size=64Features:
- Smart favicon extraction from multiple sources (PWA manifests, Apple touch icons, HTML tags)
- 30-day server-side caching with ETag/304 support
- Automatic fallback to generated favicon if none found
Get Gravatar avatars by email, MD5 hash, or path. All query parameters (except email/hash) are forwarded directly to Gravatar. You can switch from Gravatar by simply replacing the URL prefix.
GET /gravatar/{md5}?{gravatar_params}
GET /gravatar?email={email}
GET /gravatar?hash={md5}&{gravatar_params}
Examples:
# By path (drop-in replacement for Gravatar URLs)
https://api.bysages.com/gravatar/{md5}?size=200
# By email
https://api.bysages.com/gravatar?email=user@example.com
# By MD5 hash
https://api.bysages.com/gravatar?hash={md5}
# With Gravatar parameters
https://api.bysages.com/gravatar?email=user@example.com&size=200&default=identicon&rating=pgParameters:
{md5}- MD5 hash in URL path (drop-in replacement mode)email- Email address (will be MD5 hashed automatically)hash- Pre-computed MD5 hash (alternative to email)- All other parameters are forwarded to Gravatar API
Model Context Protocol server exposing all Lens services as tools via JSON-RPC 2.0 over HTTP.
POST /mcp
Setup with Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"lens": {
"url": "https://api.bysages.com/mcp"
}
}
}Available Tools:
| Tool | Description | Returns |
|---|---|---|
reader |
Extract article content from a URL (HTML/Markdown) | text |
screenshot |
Capture a screenshot of a website | image |
favicon |
Extract a website's favicon | image |
og |
Generate a dynamic Open Graph image | image |
gravatar |
Get a Gravatar avatar by email or hash | image |
img |
Transform and optimize an image (resize, crop, convert) | image |
Google Fonts compatible API with both v1 and v2 endpoints:
GET /css?family={font_family}&display=swap
GET /css2?family={font_family}&display=swap
API Differences:
| Feature | /css (v1) |
/css2 (v2) |
|---|---|---|
| Multiple fonts | family=A|B (pipe separator) |
family=A&family=B (repeated parameter) |
| Style syntax | FontName:400,700 (old) |
FontName:wght@400;700 (new, strict) |
| Variable fonts | β Not supported | β
Full support with ranges (wght@200..900) |
| Base URL | fonts.googleapis.com/css |
fonts.googleapis.com/css2 |
Parameters:
family- Font family name (required)display- Font display strategy (default: swap)subset- Font subset (default: latin)provider- Font provider (google, bunny, fontshare, fontsource, default: google)proxy- Use proxy for font files (true/false, default: false)
Examples:
# Basic font (v1 API - pipe separator)
https://api.bysages.com/css?family=Roboto:wght@400;700|Open+Sans:wght@300;400;600&display=swap
# Multiple fonts (v2 API - repeated family parameter)
https://api.bysages.com/css2?family=Inter:wght@400;700&family=Roboto:wght@300;400&display=swap
# Variable fonts with weight range (v2 only)
https://api.bysages.com/css2?family=Inter:wght@200..800&display=swap
# Font metadata
https://api.bysages.com/webfonts?sort=popularity&category=sans-serifRecommendations:
- Use
/cssfor legacy compatibility with old Google Fonts syntax - Use
/css2for modern applications with variable fonts and better optimization - Both endpoints support all font providers (Google, Bunny, Fontshare, Fontsource)
Lens is built with modern web standards and follows clean architecture principles:
- Runtime: Node.js 22+ with Nitro
- Language: TypeScript with strict type safety
- Image Proxy: IPX with Sharp
- Browser Automation: Playwright with Crawlee BrowserPool
- Caching: Redis with unstorage
- KISS (Keep It Simple): Simple, focused solutions over complex abstractions
- DRY (Don't Repeat Yourself): Shared utilities and configurations
- Graceful Degradation: Fallbacks for missing dependencies
- Type Safety: Comprehensive TypeScript coverage
- Performance First: Optimized for speed and efficiency
- Node.js 22+ runtime
- pnpm 10+ package manager
- Redis (optional, for distributed caching)
# Build the application
pnpm run build
# Start production server
pnpm run preview# Copy environment variables
cp .env.example .env
# Edit .env file to configure your settings
# nano .env
# Start the application
docker-compose up -d
# View logs
docker-compose logs -f app
# Stop the application
docker-compose downThe application will be available at http://localhost:3000
The stack includes:
- Lens application on port 3000
- Redis for distributed caching (optional but recommended)
# Pull the official image
docker pull bysages/lens:latest
# Run container with host network (recommended for accurate IP logging)
docker run -d \
--name lens \
--network host \
--env-file .env \
--restart unless-stopped \
bysages/lens:latest
# View logs
docker logs -f lens
# Stop the container
docker stop lens
docker rm lens# Build Docker image
docker build -t lens .
# Run container
docker run -d \
--name lens \
--network host \
--env-file .env \
--restart unless-stopped \
lensAll configurations are optional:
# Image Proxy Security
ALLOWED_DOMAINS=example.com,cdn.example.com
# Caching (significantly improves performance)
REDIS_URL=redis://localhost:6379See .env.example for all available options.
MIT License - see LICENSE file for details.
Built with β€οΈ by By Sages