feat: add /compare and /guides/quick-start SEO pages
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 9m51s

- Compare page: SnapAPI vs ScreenshotOne, URLBox, ApiFlash, CaptureKit, GetScreenshot
- Quick-start guide: 5-step developer tutorial with cURL, GET, SDK examples
- Both pages: dark theme, JSON-LD, OG tags, canonical URLs, mobile responsive
- Added clean URL redirects in routing
- Updated sitemap.xml and index.html nav
- Added seo-pages.test.ts (10 tests, all passing)
This commit is contained in:
Hoid 2026-03-02 12:07:08 +01:00
parent e9ee3a6c2c
commit 9d1170fb9a
6 changed files with 547 additions and 0 deletions

212
public/compare.html Normal file
View file

@ -0,0 +1,212 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Screenshot API Comparison 2026 — SnapAPI vs Alternatives | SnapAPI</title>
<meta name="description" content="Compare screenshot APIs: SnapAPI vs ScreenshotOne, URLBox, ApiFlash, CaptureKit, and GetScreenshot. Find the best screenshot API for your project.">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📸</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="canonical" href="https://snapapi.eu/compare">
<meta property="og:title" content="Screenshot API Comparison 2026 — SnapAPI vs Alternatives">
<meta property="og:description" content="Compare screenshot APIs: SnapAPI vs ScreenshotOne, URLBox, ApiFlash, CaptureKit, and GetScreenshot.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://snapapi.eu/compare">
<meta property="og:image" content="https://snapapi.eu/og-image.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Screenshot API Comparison 2026 — SnapAPI vs Alternatives">
<meta name="twitter:description" content="Compare screenshot APIs: SnapAPI vs ScreenshotOne, URLBox, ApiFlash, CaptureKit, and GetScreenshot.">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","name":"Screenshot API Comparison 2026","description":"Compare screenshot APIs: SnapAPI vs ScreenshotOne, URLBox, ApiFlash, CaptureKit, and GetScreenshot.","url":"https://snapapi.eu/compare","publisher":{"@type":"Organization","name":"SnapAPI","url":"https://snapapi.eu"}}
</script>
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{
--bg:#0a0e17;--bg2:#0f1420;--card:#141a28;--card-hover:#1a2235;
--border:#1e2a3f;--border-light:#2a3752;
--text:#f0f2f7;--text-secondary:#94a3c0;--muted:#6b7a96;
--primary:#4f8fff;--primary-light:#6da3ff;--primary-dark:#3a6fd8;--primary-glow:rgba(79,143,255,0.15);
--accent:#10b981;--accent-glow:rgba(16,185,129,0.15);
--purple:#a78bfa;--orange:#f59e0b;--pink:#ec4899;
--gradient:linear-gradient(135deg,#4f8fff 0%,#a78bfa 50%,#ec4899 100%);
--radius:12px;--radius-lg:16px;--radius-xl:24px;
}
html{scroll-behavior:smooth}
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;-webkit-font-smoothing:antialiased}
a{color:var(--primary-light);text-decoration:none;transition:color .2s}
a:hover{color:var(--primary)}
::selection{background:var(--primary);color:#fff}
.container{max-width:800px;margin:0 auto;padding:0 24px}
.btn{display:inline-flex;align-items:center;gap:8px;padding:12px 28px;border-radius:10px;font-weight:600;font-size:.95rem;border:none;cursor:pointer;transition:all .2s;font-family:inherit}
.btn-primary{background:var(--primary);color:#fff;box-shadow:0 4px 20px rgba(79,143,255,0.3)}
.btn-primary:hover{background:var(--primary-dark);transform:translateY(-1px);box-shadow:0 6px 28px rgba(79,143,255,0.4);color:#fff}
.btn-lg{padding:16px 36px;font-size:1.05rem;border-radius:12px}
nav{position:sticky;top:0;z-index:100;background:rgba(10,14,23,0.85);backdrop-filter:blur(20px);border-bottom:1px solid rgba(30,42,63,0.5);padding:0 24px}
.nav-inner{max-width:1180px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;height:64px}
.nav-logo{font-size:1.15rem;font-weight:800;display:flex;align-items:center;gap:8px;color:var(--text)}
.nav-logo span{background:var(--gradient);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.nav-links{display:flex;gap:32px;align-items:center}
.nav-links a{color:var(--muted);font-size:.9rem;font-weight:500;transition:color .2s}
.nav-links a:hover{color:var(--text)}
.nav-cta{margin-left:8px}
.nav-mobile{display:none;background:none;border:none;color:var(--text);font-size:1.5rem;cursor:pointer}
.article{padding:80px 0 60px}
.article h1{font-size:2.5rem;font-weight:800;line-height:1.2;margin-bottom:24px}
.article h2{font-size:1.6rem;font-weight:700;margin:48px 0 16px}
.article h3{font-size:1.2rem;font-weight:600;margin:32px 0 12px}
.article p{color:var(--text-secondary);font-size:1rem;line-height:1.8;margin-bottom:16px}
.article ul,.article ol{color:var(--text-secondary);margin:0 0 16px 24px;line-height:1.8}
.article li{margin-bottom:8px}
.compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin:32px 0}
.compare-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:24px;transition:border-color .2s}
.compare-card:hover{border-color:var(--border-light)}
.compare-card h3{margin:0 0 12px;font-size:1.05rem;font-weight:700;color:var(--text)}
.compare-card p{font-size:.9rem;color:var(--text-secondary);margin:0 0 12px}
.compare-card ul{margin:0;padding:0;list-style:none}
.compare-card ul li{padding:4px 0;font-size:.88rem;color:var(--text-secondary)}
.compare-card ul li::before{content:"✓ ";color:var(--accent)}
.compare-card.highlight{border-color:var(--primary);background:linear-gradient(135deg,rgba(79,143,255,0.05),rgba(167,139,250,0.05))}
.feature-list{list-style:none;padding:0;margin:24px 0}
.feature-list li{padding:12px 0;border-bottom:1px solid var(--border);font-size:.95rem;color:var(--text-secondary);display:flex;align-items:center;gap:12px}
.feature-list li .icon{font-size:1.2rem}
.cta-box{background:linear-gradient(135deg,rgba(79,143,255,0.1) 0%,rgba(167,139,250,0.1) 100%);border:1px solid rgba(79,143,255,0.2);border-radius:var(--radius-xl);padding:48px;text-align:center;margin:48px 0}
.cta-box h2{font-size:1.8rem;font-weight:800;margin-bottom:12px}
.cta-box p{color:var(--text-secondary);margin-bottom:24px}
footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(--bg2)}
.footer-grid{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:40px;margin-bottom:40px}
.footer-brand h4{font-size:1.1rem;font-weight:800;margin-bottom:12px;display:flex;align-items:center;gap:8px}
.footer-brand p{color:var(--muted);font-size:.85rem;line-height:1.6;max-width:280px}
.footer-col h5{font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;color:var(--muted);margin-bottom:16px}
.footer-col a{display:block;color:var(--text-secondary);font-size:.88rem;padding:4px 0;transition:color .2s}
.footer-col a:hover{color:var(--text)}
.footer-bottom{max-width:1180px;margin:0 auto;padding-top:24px;border-top:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;font-size:.8rem;color:var(--muted)}
@media(max-width:640px){
.article{padding:40px 0 30px}
.article h1{font-size:1.8rem}
.compare-grid{grid-template-columns:1fr}
.nav-links{display:none;flex-direction:column;position:absolute;top:64px;left:0;right:0;background:rgba(10,14,23,0.97);backdrop-filter:blur(20px);border-bottom:1px solid var(--border);padding:16px 24px;gap:16px;z-index:99}
.nav-links.show{display:flex}
.nav-mobile{display:block}
.footer-grid{grid-template-columns:1fr}
}
</style>
</head>
<body>
<nav>
<div class="nav-inner">
<a href="/" class="nav-logo">📸 <span>SnapAPI</span></a>
<div class="nav-links">
<a href="/#features">Features</a>
<a href="/#playground">Try It Free</a>
<a href="/#pricing">Pricing</a>
<a href="/docs">API Docs</a>
<a href="/#pricing" class="btn btn-primary btn-sm nav-cta">Get API Key</a>
</div>
<button class="nav-mobile" onclick="document.querySelector('.nav-links').classList.toggle('show')" aria-label="Menu"></button>
</div>
</nav>
<article class="article">
<div class="container">
<h1>Screenshot API Comparison 2026</h1>
<p>Choosing the right screenshot API depends on your requirements — pricing, data residency, features, and developer experience. Here's an honest look at how the major screenshot APIs compare so you can pick the best fit for your project.</p>
<h2>The Contenders</h2>
<div class="compare-grid">
<div class="compare-card highlight">
<h3>📸 SnapAPI</h3>
<p>EU-hosted screenshot API with simple EUR pricing.</p>
<ul>
<li>EU data residency (Germany)</li>
<li>POST &amp; GET endpoints</li>
<li>Built-in response caching</li>
<li>Free playground, no signup</li>
<li>Node.js &amp; Python SDKs</li>
<li>Pricing in EUR</li>
</ul>
</div>
<div class="compare-card">
<h3>ScreenshotOne</h3>
<p>Feature-rich API with global CDN.</p>
<ul>
<li>Extensive rendering options</li>
<li>US-based infrastructure</li>
<li>USD pricing</li>
</ul>
</div>
<div class="compare-card">
<h3>URLBox</h3>
<p>Established screenshot service with retina support.</p>
<ul>
<li>Retina rendering</li>
<li>Webhook notifications</li>
<li>USD pricing</li>
</ul>
</div>
<div class="compare-card">
<h3>ApiFlash</h3>
<p>Chrome-based screenshot API with CDN caching.</p>
<ul>
<li>AWS-powered rendering</li>
<li>Built-in CDN</li>
<li>USD pricing</li>
</ul>
</div>
<div class="compare-card">
<h3>CaptureKit</h3>
<p>Modern API with generous free tier.</p>
<ul>
<li>Multiple output formats</li>
<li>Custom viewport sizes</li>
<li>USD pricing</li>
</ul>
</div>
<div class="compare-card">
<h3>GetScreenshot</h3>
<p>Simple screenshot API for quick integrations.</p>
<ul>
<li>Simple REST API</li>
<li>PNG &amp; JPEG output</li>
<li>USD pricing</li>
</ul>
</div>
</div>
<h2>Why SnapAPI?</h2>
<p>Every API on this list can take a screenshot. What sets SnapAPI apart is where and how it does it:</p>
<ul class="feature-list">
<li><span class="icon">🇪🇺</span> <strong>EU-hosted &amp; GDPR compliant</strong> — All rendering happens on servers in Germany. Your data never leaves the EU. No extra DPAs or compliance headaches.</li>
<li><span class="icon">💶</span> <strong>Simple EUR pricing</strong> — No currency conversion, no hidden fees. Plans start at €9/month with clear per-screenshot pricing.</li>
<li><span class="icon">🔗</span> <strong>GET &amp; POST endpoints</strong> — Use GET requests to embed screenshots directly in <code>&lt;img&gt;</code> tags. No server-side code needed for simple use cases.</li>
<li><span class="icon"></span> <strong>Built-in caching</strong> — Response caching out of the box. Repeated requests for the same URL return cached results instantly.</li>
<li><span class="icon">🎮</span> <strong>Free playground</strong> — Try the API in your browser without creating an account or entering payment details.</li>
<li><span class="icon">📦</span> <strong>Official SDKs</strong> — First-class Node.js and Python SDKs to get you started in minutes.</li>
</ul>
<div class="cta-box">
<h2>Try SnapAPI Free</h2>
<p>No signup required. Test screenshots in the playground, then get an API key when you're ready.</p>
<a href="/#pricing" class="btn btn-primary btn-lg">Get Your API Key →</a>
</div>
</div>
</article>
<footer>
<div class="footer-grid">
<div class="footer-brand"><h4>📸 SnapAPI</h4><p>The EU-hosted screenshot API for developers. Convert any URL to a pixel-perfect image with a simple API call.</p></div>
<div class="footer-col"><h5>Product</h5><a href="/#features">Features</a><a href="/#pricing">Pricing</a><a href="/#playground">Playground</a><a href="/docs">API Docs</a></div>
<div class="footer-col"><h5>Developers</h5><a href="/docs">Swagger / OpenAPI</a><a href="/health">Status</a><a href="/guides/quick-start">Quick-Start Guide</a></div>
<div class="footer-col"><h5>Legal</h5><a href="/impressum.html">Impressum</a><a href="/privacy.html">Privacy Policy</a><a href="/terms.html">Terms of Service</a></div>
</div>
<div class="footer-bottom">
<span>© 2026 Cloonar Technologies GmbH · FN 631089y · ATU81280034</span>
<span>Linzer Straße 192/1/2, 1140 Wien, Austria 🇦🇹</span>
<span>EU-hosted 🇪🇺 · All data stays in Europe</span>
</div>
</footer>
</body>
</html>

View file

@ -0,0 +1,220 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Quick-Start Guide — Take Your First Screenshot with SnapAPI</title>
<meta name="description" content="Learn how to use SnapAPI in 5 minutes. Step-by-step guide: get an API key, take a screenshot with cURL, embed with GET, use caching, and try the SDKs.">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📸</text></svg>">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="canonical" href="https://snapapi.eu/guides/quick-start">
<meta property="og:title" content="Quick-Start Guide — Take Your First Screenshot with SnapAPI">
<meta property="og:description" content="From zero to first screenshot in 5 minutes. cURL, GET embedding, caching, and SDK examples.">
<meta property="og:type" content="article">
<meta property="og:url" content="https://snapapi.eu/guides/quick-start">
<meta property="og:image" content="https://snapapi.eu/og-image.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Quick-Start Guide — Take Your First Screenshot with SnapAPI">
<meta name="twitter:description" content="From zero to first screenshot in 5 minutes. cURL, GET embedding, caching, and SDK examples.">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"HowTo","name":"Take Your First Screenshot with SnapAPI","description":"Step-by-step guide from zero to first screenshot using the SnapAPI screenshot API.","step":[{"@type":"HowToStep","position":1,"name":"Get an API key","text":"Sign up for a SnapAPI plan to get your API key."},{"@type":"HowToStep","position":2,"name":"Take your first screenshot","text":"Use cURL to call the POST endpoint and capture a screenshot."},{"@type":"HowToStep","position":3,"name":"Use the GET endpoint for embedding","text":"Embed screenshots directly in img tags using GET requests."},{"@type":"HowToStep","position":4,"name":"Use caching headers","text":"Leverage built-in response caching for faster repeated requests."},{"@type":"HowToStep","position":5,"name":"Try the SDKs","text":"Use the official Node.js or Python SDK for easier integration."}],"publisher":{"@type":"Organization","name":"SnapAPI","url":"https://snapapi.eu"}}
</script>
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{
--bg:#0a0e17;--bg2:#0f1420;--card:#141a28;--card-hover:#1a2235;
--border:#1e2a3f;--border-light:#2a3752;
--text:#f0f2f7;--text-secondary:#94a3c0;--muted:#6b7a96;
--primary:#4f8fff;--primary-light:#6da3ff;--primary-dark:#3a6fd8;--primary-glow:rgba(79,143,255,0.15);
--accent:#10b981;--accent-glow:rgba(16,185,129,0.15);
--purple:#a78bfa;--orange:#f59e0b;--pink:#ec4899;
--gradient:linear-gradient(135deg,#4f8fff 0%,#a78bfa 50%,#ec4899 100%);
--radius:12px;--radius-lg:16px;--radius-xl:24px;
}
html{scroll-behavior:smooth}
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;-webkit-font-smoothing:antialiased}
a{color:var(--primary-light);text-decoration:none;transition:color .2s}
a:hover{color:var(--primary)}
::selection{background:var(--primary);color:#fff}
.container{max-width:800px;margin:0 auto;padding:0 24px}
.btn{display:inline-flex;align-items:center;gap:8px;padding:12px 28px;border-radius:10px;font-weight:600;font-size:.95rem;border:none;cursor:pointer;transition:all .2s;font-family:inherit}
.btn-primary{background:var(--primary);color:#fff;box-shadow:0 4px 20px rgba(79,143,255,0.3)}
.btn-primary:hover{background:var(--primary-dark);transform:translateY(-1px);box-shadow:0 6px 28px rgba(79,143,255,0.4);color:#fff}
.btn-lg{padding:16px 36px;font-size:1.05rem;border-radius:12px}
nav{position:sticky;top:0;z-index:100;background:rgba(10,14,23,0.85);backdrop-filter:blur(20px);border-bottom:1px solid rgba(30,42,63,0.5);padding:0 24px}
.nav-inner{max-width:1180px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;height:64px}
.nav-logo{font-size:1.15rem;font-weight:800;display:flex;align-items:center;gap:8px;color:var(--text)}
.nav-logo span{background:var(--gradient);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.nav-links{display:flex;gap:32px;align-items:center}
.nav-links a{color:var(--muted);font-size:.9rem;font-weight:500;transition:color .2s}
.nav-links a:hover{color:var(--text)}
.nav-cta{margin-left:8px}
.nav-mobile{display:none;background:none;border:none;color:var(--text);font-size:1.5rem;cursor:pointer}
.article{padding:80px 0 60px}
.article h1{font-size:2.5rem;font-weight:800;line-height:1.2;margin-bottom:24px}
.article h2{font-size:1.6rem;font-weight:700;margin:48px 0 16px}
.article h3{font-size:1.2rem;font-weight:600;margin:32px 0 12px}
.article p{color:var(--text-secondary);font-size:1rem;line-height:1.8;margin-bottom:16px}
.article ul,.article ol{color:var(--text-secondary);margin:0 0 16px 24px;line-height:1.8}
.article li{margin-bottom:8px}
.step{background:var(--card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:28px;margin:24px 0}
.step-number{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;background:var(--primary);color:#fff;font-weight:700;font-size:.9rem;margin-bottom:12px}
.code-window{background:var(--card);border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;margin:24px 0;box-shadow:0 10px 40px rgba(0,0,0,0.2)}
.code-titlebar{display:flex;align-items:center;gap:8px;padding:14px 20px;background:rgba(0,0,0,0.2);border-bottom:1px solid var(--border)}
.code-dot{width:12px;height:12px;border-radius:50%}
.code-dot:nth-child(1){background:#ff5f57}.code-dot:nth-child(2){background:#ffbd2e}.code-dot:nth-child(3){background:#28c840}
.code-titlebar span{flex:1;text-align:center;font-size:.8rem;color:var(--muted);font-weight:500}
.code-body{padding:24px;font-family:'JetBrains Mono',monospace;font-size:.85rem;line-height:1.9;overflow-x:auto;color:var(--text-secondary)}
.code-body .kw{color:var(--purple)}.code-body .str{color:var(--accent)}.code-body .cmt{color:#475569;font-style:italic}.code-body .fn{color:var(--primary-light)}.code-body .prop{color:var(--orange)}
.cta-box{background:linear-gradient(135deg,rgba(79,143,255,0.1) 0%,rgba(167,139,250,0.1) 100%);border:1px solid rgba(79,143,255,0.2);border-radius:var(--radius-xl);padding:48px;text-align:center;margin:48px 0}
.cta-box h2{font-size:1.8rem;font-weight:800;margin-bottom:12px}
.cta-box p{color:var(--text-secondary);margin-bottom:24px}
.related{margin:48px 0;padding:32px;background:var(--card);border:1px solid var(--border);border-radius:var(--radius-lg)}
.related h3{font-size:1.1rem;font-weight:700;margin-bottom:16px}
.related a{display:block;padding:8px 0;font-size:.95rem}
footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(--bg2)}
.footer-grid{max-width:1180px;margin:0 auto;display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:40px;margin-bottom:40px}
.footer-brand h4{font-size:1.1rem;font-weight:800;margin-bottom:12px;display:flex;align-items:center;gap:8px}
.footer-brand p{color:var(--muted);font-size:.85rem;line-height:1.6;max-width:280px}
.footer-col h5{font-size:.8rem;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;color:var(--muted);margin-bottom:16px}
.footer-col a{display:block;color:var(--text-secondary);font-size:.88rem;padding:4px 0;transition:color .2s}
.footer-col a:hover{color:var(--text)}
.footer-bottom{max-width:1180px;margin:0 auto;padding-top:24px;border-top:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;font-size:.8rem;color:var(--muted)}
@media(max-width:640px){
.article{padding:40px 0 30px}
.article h1{font-size:1.8rem}
.nav-links{display:none;flex-direction:column;position:absolute;top:64px;left:0;right:0;background:rgba(10,14,23,0.97);backdrop-filter:blur(20px);border-bottom:1px solid var(--border);padding:16px 24px;gap:16px;z-index:99}
.nav-links.show{display:flex}
.nav-mobile{display:block}
.footer-grid{grid-template-columns:1fr}
}
</style>
</head>
<body>
<nav>
<div class="nav-inner">
<a href="/" class="nav-logo">📸 <span>SnapAPI</span></a>
<div class="nav-links">
<a href="/#features">Features</a>
<a href="/#playground">Try It Free</a>
<a href="/#pricing">Pricing</a>
<a href="/docs">API Docs</a>
<a href="/#pricing" class="btn btn-primary btn-sm nav-cta">Get API Key</a>
</div>
<button class="nav-mobile" onclick="document.querySelector('.nav-links').classList.toggle('show')" aria-label="Menu"></button>
</div>
</nav>
<article class="article">
<div class="container">
<h1>Quick-Start Guide: Your First Screenshot in 5 Minutes</h1>
<p>This guide walks you through everything you need to go from zero to capturing screenshots with SnapAPI. No prior experience required.</p>
<div class="step">
<div class="step-number">1</div>
<h2>Get an API key</h2>
<p>Head to the <a href="/#pricing">pricing page</a> and pick a plan. You'll receive your API key immediately after signing up. Plans start at €9/month.</p>
<p>Want to try first? Use the <a href="/#playground">free playground</a> — no signup needed.</p>
</div>
<div class="step">
<div class="step-number">2</div>
<h2>Take your first screenshot</h2>
<p>Use <code>curl</code> to call the POST endpoint and capture a screenshot:</p>
<div class="code-window">
<div class="code-titlebar"><span class="code-dot"></span><span class="code-dot"></span><span class="code-dot"></span><span>cURL</span></div>
<div class="code-body"><pre>curl -X POST https://snapapi.eu/v1/screenshot \
-H <span class="str">"Content-Type: application/json"</span> \
-H <span class="str">"X-API-Key: YOUR_API_KEY"</span> \
-d <span class="str">'{"url": "https://example.com", "format": "png"}'</span> \
--output screenshot.png</pre></div>
</div>
<p>That's it — you'll have a <code>screenshot.png</code> file on your machine.</p>
</div>
<div class="step">
<div class="step-number">3</div>
<h2>Use the GET endpoint for embedding</h2>
<p>SnapAPI supports GET requests, which means you can embed screenshots directly in <code>&lt;img&gt;</code> tags — no server-side code needed:</p>
<div class="code-window">
<div class="code-titlebar"><span class="code-dot"></span><span class="code-dot"></span><span class="code-dot"></span><span>HTML</span></div>
<div class="code-body"><pre>&lt;img src=<span class="str">"https://snapapi.eu/v1/screenshot?url=https://example.com&amp;format=png&amp;apiKey=YOUR_API_KEY"</span>
alt=<span class="str">"Screenshot of example.com"</span> /&gt;</pre></div>
</div>
<p>This is perfect for dashboards, link previews, and documentation where you want live screenshots without any backend logic.</p>
</div>
<div class="step">
<div class="step-number">4</div>
<h2>Use caching headers</h2>
<p>SnapAPI includes built-in response caching. When you request the same URL multiple times, subsequent requests return the cached result instantly — saving you both time and credits.</p>
<p>Cache behavior is automatic. The <code>Cache-Control</code> headers in the response tell you the cache status.</p>
</div>
<div class="step">
<div class="step-number">5</div>
<h2>Try the Node.js and Python SDKs</h2>
<p>For deeper integrations, use the official SDKs:</p>
<div class="code-window">
<div class="code-titlebar"><span class="code-dot"></span><span class="code-dot"></span><span class="code-dot"></span><span>Node.js</span></div>
<div class="code-body"><pre><span class="kw">import</span> { SnapAPI } <span class="kw">from</span> <span class="str">'snapapi'</span>;
<span class="kw">const</span> client = <span class="kw">new</span> <span class="fn">SnapAPI</span>(<span class="str">'YOUR_API_KEY'</span>);
<span class="kw">const</span> screenshot = <span class="kw">await</span> client.<span class="fn">take</span>({
url: <span class="str">'https://example.com'</span>,
format: <span class="str">'png'</span>,
width: <span class="prop">1280</span>,
height: <span class="prop">720</span>
});</pre></div>
</div>
<div class="code-window">
<div class="code-titlebar"><span class="code-dot"></span><span class="code-dot"></span><span class="code-dot"></span><span>Python</span></div>
<div class="code-body"><pre><span class="kw">from</span> snapapi <span class="kw">import</span> SnapAPI
client = <span class="fn">SnapAPI</span>(<span class="str">"YOUR_API_KEY"</span>)
screenshot = client.<span class="fn">take</span>(
url=<span class="str">"https://example.com"</span>,
format=<span class="str">"png"</span>,
width=<span class="prop">1280</span>,
height=<span class="prop">720</span>
)</pre></div>
</div>
</div>
<div class="cta-box">
<h2>Ready to Build?</h2>
<p>Get your API key and start capturing screenshots in production.</p>
<a href="/#pricing" class="btn btn-primary btn-lg">Get Your API Key →</a>
</div>
<div class="related">
<h3>Next Steps</h3>
<a href="/docs">Full API Documentation (Swagger) →</a>
<a href="/use-cases/social-media-previews">Use Case: Generate OG Images →</a>
<a href="/compare">Compare SnapAPI to Alternatives →</a>
</div>
</div>
</article>
<footer>
<div class="footer-grid">
<div class="footer-brand"><h4>📸 SnapAPI</h4><p>The EU-hosted screenshot API for developers. Convert any URL to a pixel-perfect image with a simple API call.</p></div>
<div class="footer-col"><h5>Product</h5><a href="/#features">Features</a><a href="/#pricing">Pricing</a><a href="/#playground">Playground</a><a href="/docs">API Docs</a></div>
<div class="footer-col"><h5>Developers</h5><a href="/docs">Swagger / OpenAPI</a><a href="/health">Status</a><a href="/guides/quick-start">Quick-Start Guide</a></div>
<div class="footer-col"><h5>Legal</h5><a href="/impressum.html">Impressum</a><a href="/privacy.html">Privacy Policy</a><a href="/terms.html">Terms of Service</a></div>
</div>
<div class="footer-bottom">
<span>© 2026 Cloonar Technologies GmbH · FN 631089y · ATU81280034</span>
<span>Linzer Straße 192/1/2, 1140 Wien, Austria 🇦🇹</span>
<span>EU-hosted 🇪🇺 · All data stays in Europe</span>
</div>
</footer>
</body>
</html>

View file

@ -244,6 +244,8 @@ footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(
<a href="#docs">API Docs</a> <a href="#docs">API Docs</a>
<a href="/docs" target="_blank">Swagger</a> <a href="/docs" target="_blank">Swagger</a>
<a href="/usage">Usage</a> <a href="/usage">Usage</a>
<a href="/compare">Compare</a>
<a href="/guides/quick-start">Quick Start</a>
<a href="#pricing" class="btn btn-primary btn-sm nav-cta">Get API Key</a> <a href="#pricing" class="btn btn-primary btn-sm nav-cta">Get API Key</a>
</div> </div>
<button class="nav-mobile" onclick="document.querySelector('.nav-links').classList.toggle('show')" aria-label="Menu"></button> <button class="nav-mobile" onclick="document.querySelector('.nav-links').classList.toggle('show')" aria-label="Menu"></button>

View file

@ -5,6 +5,8 @@
<url><loc>https://snapapi.eu/use-cases/social-media-previews</loc><changefreq>monthly</changefreq><priority>0.7</priority></url> <url><loc>https://snapapi.eu/use-cases/social-media-previews</loc><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://snapapi.eu/use-cases/website-monitoring</loc><changefreq>monthly</changefreq><priority>0.7</priority></url> <url><loc>https://snapapi.eu/use-cases/website-monitoring</loc><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://snapapi.eu/use-cases/pdf-reports</loc><changefreq>monthly</changefreq><priority>0.7</priority></url> <url><loc>https://snapapi.eu/use-cases/pdf-reports</loc><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://snapapi.eu/compare</loc><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://snapapi.eu/guides/quick-start</loc><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://snapapi.eu/status</loc><changefreq>always</changefreq><priority>0.3</priority></url> <url><loc>https://snapapi.eu/status</loc><changefreq>always</changefreq><priority>0.3</priority></url>
<url><loc>https://snapapi.eu/impressum.html</loc><changefreq>yearly</changefreq><priority>0.2</priority></url> <url><loc>https://snapapi.eu/impressum.html</loc><changefreq>yearly</changefreq><priority>0.2</priority></url>
<url><loc>https://snapapi.eu/privacy.html</loc><changefreq>yearly</changefreq><priority>0.2</priority></url> <url><loc>https://snapapi.eu/privacy.html</loc><changefreq>yearly</changefreq><priority>0.2</priority></url>

View file

@ -135,6 +135,10 @@ for (const page of ["social-media-previews", "website-monitoring", "pdf-reports"
app.get(`/use-cases/${page}`, (_req, res) => res.redirect(301, `/use-cases/${page}.html`)); app.get(`/use-cases/${page}`, (_req, res) => res.redirect(301, `/use-cases/${page}.html`));
} }
// Clean URLs for SEO pages
app.get("/compare", (_req, res) => res.redirect(301, "/compare.html"));
app.get("/guides/quick-start", (_req, res) => res.redirect(301, "/guides/quick-start.html"));
// Static files (landing page) // Static files (landing page)
app.use(express.static(path.join(__dirname, "../public"), { etag: true })); app.use(express.static(path.join(__dirname, "../public"), { etag: true }));

View file

@ -0,0 +1,107 @@
import { describe, it, expect } from 'vitest'
import request from 'supertest'
import express from 'express'
import path from 'path'
import { fileURLToPath } from 'url'
import fs from 'fs'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const publicDir = path.join(__dirname, '../../../public')
function createApp() {
const app = express()
// Clean URL redirects matching index.ts
app.get('/compare', (_req, res) => res.redirect(301, '/compare.html'))
app.get('/guides/quick-start', (_req, res) => res.redirect(301, '/guides/quick-start.html'))
app.use(express.static(publicDir, { etag: true }))
return app
}
describe('Compare Page', () => {
const app = createApp()
it('GET /compare.html returns 200', async () => {
const res = await request(app).get('/compare.html')
expect(res.status).toBe(200)
expect(res.headers['content-type']).toContain('text/html')
})
it('GET /compare redirects 301 to .html', async () => {
const res = await request(app).get('/compare')
expect(res.status).toBe(301)
expect(res.headers.location).toBe('/compare.html')
})
it('contains required SEO elements', async () => {
const res = await request(app).get('/compare.html')
const html = res.text
expect(html).toMatch(/<title>.+<\/title>/)
expect(html).toMatch(/<meta name="description" content=".+"/)
expect(html).toMatch(/<meta property="og:title"/)
expect(html).toMatch(/<meta property="og:description"/)
expect(html).toMatch(/<meta property="og:type" content="website"/)
expect(html).toMatch(/<link rel="canonical"/)
expect(html).toMatch(/<meta name="twitter:card"/)
expect(html).toContain('"@type":"WebPage"')
})
it('mentions competitors factually', async () => {
const res = await request(app).get('/compare.html')
const html = res.text
for (const competitor of ['ScreenshotOne', 'URLBox', 'ApiFlash', 'CaptureKit', 'GetScreenshot']) {
expect(html).toContain(competitor)
}
})
})
describe('Quick-Start Guide', () => {
const app = createApp()
it('GET /guides/quick-start.html returns 200', async () => {
const res = await request(app).get('/guides/quick-start.html')
expect(res.status).toBe(200)
expect(res.headers['content-type']).toContain('text/html')
})
it('GET /guides/quick-start redirects 301 to .html', async () => {
const res = await request(app).get('/guides/quick-start')
expect(res.status).toBe(301)
expect(res.headers.location).toBe('/guides/quick-start.html')
})
it('contains required SEO elements', async () => {
const res = await request(app).get('/guides/quick-start.html')
const html = res.text
expect(html).toMatch(/<title>.+<\/title>/)
expect(html).toMatch(/<meta name="description" content=".+"/)
expect(html).toMatch(/<meta property="og:title"/)
expect(html).toMatch(/<meta property="og:description"/)
expect(html).toMatch(/<link rel="canonical"/)
expect(html).toMatch(/<meta name="twitter:card"/)
expect(html).toContain('"@type":"HowTo"')
})
it('contains step-by-step content', async () => {
const res = await request(app).get('/guides/quick-start.html')
const html = res.text
expect(html).toContain('curl')
expect(html).toContain('API key')
expect(html).toContain('GET')
})
})
describe('Sitemap & Index updates', () => {
it('sitemap contains new URLs', () => {
const sitemap = fs.readFileSync(path.join(publicDir, 'sitemap.xml'), 'utf-8')
expect(sitemap).toContain('https://snapapi.eu/compare')
expect(sitemap).toContain('https://snapapi.eu/guides/quick-start')
})
it('index.html has links to new pages', () => {
const index = fs.readFileSync(path.join(publicDir, 'index.html'), 'utf-8')
expect(index).toContain('/compare')
expect(index).toContain('/guides/quick-start')
})
})