URL'den ekran görüntüsü al
Kendi sunucunuzda çalışan, Playwright tabanlı screenshot servisi. Tek bir HTTP isteği ile herhangi bir web sayfasının PNG veya JPEG görüntüsünü alın — ScreenshotOne benzeri sözleşme, kota sınırı yok.
Hızlı başlangıç
Üç adımda ilk screenshot'unuzu alın.
1. API anahtarını ayarlayın
Sunucudaki .env dosyasında ACCESS_KEY değerini belirleyin. Bu key
harici bir servisten gelmez — siz üretirsiniz.
ACCESS_KEY=uzun-ve-rastgele-bir-anahtar-buraya
2. Sunucuyu çalıştırın
npm install
npx playwright install chromium
npm start
3. İlk isteği gönderin
curl -o screenshot.png \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
"/take?url=https://example.com"
image/png veya
image/jpeg). JSON değildir.
Kimlik doğrulama
/take endpoint'i kimlik doğrulama gerektirir. /health ve bu docs
sayfası herkese açıktır.
| Yöntem | Örnek | Önerilen |
|---|---|---|
| Header | X-Access-Key: YOUR_KEY |
Evet — loglarda URL'de görünmez |
| Alternatif header | X-Api-Key: YOUR_KEY |
Evet |
| Query | ?access_key=YOUR_KEY |
Sadece sunucu tarafı veya <img> için |
Hatalı key → 401
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing access key"
}
}
Base URL
Tüm endpoint'ler bu adrese göredir. Uygulamanızda tek bir değişken olarak saklayın.
Endpoint'ler
| Method | Path | Auth | Açıklama |
|---|---|---|---|
GET |
/ |
Hayır | Test arayüzü |
GET |
/docs |
Hayır | Bu dokümantasyon |
GET |
/health |
Hayır | Sağlık kontrolü |
GET |
/take |
Evet | Screenshot al |
GET /health
Docker healthcheck, uptime monitor ve deploy doğrulaması için kullanın.
200 OK — application/json
{
"status": "ok",
"timestamp": "2026-05-19T12:00:00.000Z"
}
GET /take
Hedef URL'yi headless Chromium ile açar, sayfayı render eder ve ekran görüntüsünü döndürür.
İşlem akışı
* auto_consent=true ise
Örnek istek
GET /take?url=https://example.com&format=png&full_page=false HTTP/1.1
Host: your-server.com
X-Access-Key: YOUR_ACCESS_KEY
Başarılı yanıt
| Alan | Değer |
|---|---|
| Status | 200 |
| Content-Type | image/png veya image/jpeg |
| Cache-Control | no-store |
| Body | Binary görüntü |
Query parametreleri
/take endpoint'ine eklenebilir tüm parametreler:
| Parametre | Zorunlu | Varsayılan | Açıklama |
|---|---|---|---|
url |
Evet | — | Hedef sayfa. https:// yoksa otomatik eklenir. |
access_key |
Evet* | — | API anahtarı (*header ile gönderilebilir) |
format |
Hayır | png |
png, jpeg, jpg |
viewport_width |
Hayır | 1280 |
320 – 3840 px |
viewport_height |
Hayır | 720 |
240 – 2160 px |
full_page |
Hayır | false |
Tüm kaydırılabilir sayfa |
delay |
Hayır | 0 |
Yükleme sonrası bekleme (ms), max 10000 |
block_ads |
Hayır | true |
Reklam/tracker domain engeli |
auto_consent |
Hayır | false |
Cookie banner (EN, DE, IT, FR, NL, ES, TR) |
timeout |
Hayır | 30000 |
Navigation timeout (ms), max 60000 |
Boolean değerler
full_page, block_ads, auto_consent için:
- true:
true,1,yes - false:
false,0,no
Örnek URL'ler
# Basit
/take?url=https://example.com
# Tam sayfa + cookie + gecikme
/take?url=https://site.com&full_page=true&auto_consent=true&delay=2000
# Mobil viewport
/take?url=https://site.com&viewport_width=390&viewport_height=844
Hata kodları
Hata durumunda yanıt JSON olur; görüntü dönmez.
| HTTP | error.code |
Açıklama |
|---|---|---|
| 400 | invalid_url | URL geçersiz, eksik veya SSRF engeli |
| 401 | unauthorized | Access key hatalı/eksik |
| 408 | timeout | Sayfa yükleme zaman aşımı |
| 422 | navigation_failed | Sayfa açılamadı (DNS, SSL…) |
| 429 | — | Rate limit aşıldı |
| 500 | internal_error | Sunucu hatası |
{
"error": {
"code": "invalid_url",
"message": "Private IP addresses are not allowed"
}
}
Rate limiting
IP başına varsayılan 60 istek / 60 saniye. Aşımda 429 Too Many Requests.
RATE_LIMIT_MAX=60
RATE_LIMIT_TIME_WINDOW=60000
Uygulamana entegrasyon
Diğer uygulamanızdan kullanırken önerilen mimari:
-
API key'i backend'de tutun —
SCREENSHOT_API_URLveSCREENSHOT_API_KEYenvironment variable olarak. -
Frontend doğrudan çağırmasın — key sızar. Kendi API'nize
POST /api/screenshotgibi bir endpoint ekleyin; o Screenshot API'yi çağırsın. - Timeout'u yüksek tutun — screenshot 5–30 sn sürebilir. HTTP client timeout en az 60–120 sn olsun.
-
Hata JSON'unu parse edin —
res.okfalse ise body JSON'dur. - Görüntüyü cache'leyin — aynı URL için S3/CDN'e kaydedip tekrar kullanın.
{ "url": "https://..." } gönderir → sunucunuz
Screenshot API'ye istek atar → dönen PNG'yi storage'a yazar → public URL döner.
Kod örnekleri
Base URL bu sunucuya göre otomatik doldurulur:
async function captureScreenshot(targetUrl) {
const params = new URLSearchParams({
url: targetUrl,
format: 'png',
delay: '1500',
auto_consent: 'true',
});
const res = await fetch(`${API_BASE}/take?${params}`, {
headers: { 'X-Access-Key': API_KEY },
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error?.message ?? 'Screenshot failed');
}
return Buffer.from(await res.arrayBuffer()); // Node
// return await res.blob(); // Browser
}
const API_BASE = 'BASE_PLACEHOLDER';
const API_KEY = process.env.SCREENSHOT_API_KEY;
app.post('/api/screenshot', async (req, res) => {
const { url } = req.body;
if (!url) return res.status(400).json({ error: 'url required' });
const qs = new URLSearchParams({ url, format: 'png', delay: '2000' });
const apiRes = await fetch(`${process.env.SCREENSHOT_API_URL}/take?${qs}`, {
headers: { 'X-Access-Key': process.env.SCREENSHOT_API_KEY },
signal: AbortSignal.timeout(120_000),
});
if (!apiRes.ok) {
const err = await apiRes.json();
return res.status(apiRes.status).json(err);
}
const buffer = Buffer.from(await apiRes.arrayBuffer());
res.set('Content-Type', apiRes.headers.get('content-type'));
res.send(buffer);
});
$query = http_build_query([
'url' => 'https://example.com',
'format' => 'png',
'full_page' => 'true',
]);
$ctx = stream_context_create([
'http' => [
'header' => "X-Access-Key: " . getenv('SCREENSHOT_API_KEY'),
'timeout' => 120,
],
]);
$image = file_get_contents(
getenv('SCREENSHOT_API_URL') . '/take?' . $query,
false,
$ctx
);
file_put_contents('screenshot.png', $image);
import os
import requests
def capture(url: str) -> bytes:
r = requests.get(
f"{os.environ['SCREENSHOT_API_URL']}/take",
params={
"url": url,
"format": "png",
"auto_consent": "true",
"delay": 2000,
},
headers={"X-Access-Key": os.environ["SCREENSHOT_API_KEY"]},
timeout=120,
)
r.raise_for_status()
return r.content
image = capture("https://example.com")
open("out.png", "wb").write(image)
curl -o out.png \
-H "X-Access-Key: $SCREENSHOT_API_KEY" \
"$SCREENSHOT_API_URL/take?url=https://example.com&delay=2000"
ScreenshotOne geçişi
Daha önce ScreenshotOne kullanıyorsanız minimum değişiklik:
| ScreenshotOne | Bu API |
|---|---|
api.screenshotone.com/take |
/take |
access_key | Aynı isim veya header |
url, full_page, delay | Aynı |
viewport_width/height | Aynı |
format=webp | Desteklenmiyor — png/jpeg kullanın |
En iyi pratikler
- SPA siteler için
delay=2000veya daha fazla kullanın. - Cookie banner için
auto_consent=truedeneyin; her sitede çalışmaz. - Yavaş siteler için
timeout=45000artırın. - Mobil önizleme için viewport 390×844 gibi değerler verin.
- Production'da Docker +
shm_size: 1gbkullanın.
Sunucu yapılandırması
Bunlar istemci parametresi değil; sunucu .env dosyasından okunur.
| Değişken | Varsayılan | Açıklama |
|---|---|---|
PORT | 3000 | HTTP port |
ACCESS_KEY | — | Zorunlu API anahtarı |
MAX_CONCURRENT | 3 | Eşzamanlı screenshot |
DEFAULT_TIMEOUT | 30000 | Varsayılan timeout (ms) |
MAX_TIMEOUT | 60000 | Max timeout (ms) |
RATE_LIMIT_MAX | 60 | Rate limit |
ALLOWED_DOMAINS | — | Opsiyonel domain whitelist |
Güvenlik
- SSRF: localhost ve özel IP'ler engellenir.
ALLOWED_DOMAINSile sadece izinli siteleri screenshot alabilirsiniz.- Access key asla Git'e commit edilmemeli.
- Production'da TLS (Nginx/Caddy) zorunlu sayılmalı.
Sınırlamalar
| Özellik | Durum |
|---|---|
| WebP format | Desteklenmiyor |
| POST /take | Henüz yok |
| HTML string → screenshot | Henüz yok |
| Cookie consent | Heuristik, %100 değil |