How to Make Website Previews for an Indian Startup Directory
Build a reliable startup directory preview pipeline with Playwright or a screenshot API, stable storage, refresh jobs, and useful fallbacks.
For an Indian startup directory, capture each company’s public website in a background job, save the resulting image under a stable key for that listing, and display it in a consistent card layout. Use Playwright when you need control over browser rendering and image processing; use a hosted screenshot API when you want a managed capture endpoint. Keep the last successful preview if a refresh fails, and refresh images when a listing changes or on a schedule.
This guide covers a Playwright implementation in Node.js, a hosted API option, URL-handling considerations, storage and refresh design, troubleshooting, and cost and reliability tradeoffs. The India context matters for your audience, but the sources reviewed here do not establish regional availability, data residency, or specific Indian legal requirements; verify those for your own product.
1. Design the preview workflow
A preview should not be generated on the request path that accepts a startup submission. A slow or unavailable website could otherwise delay the submission. Instead, treat capture as background work. That queue recommendation is an engineering inference from the documented capture-and-store workflow.
- Accept a website URL and normalize it into a canonical form for the listing.
- Validate the URL and apply server-side protections before fetching a user-supplied destination. The cited capture documentation does not prescribe a security design, so choose safeguards appropriate to your infrastructure.
- Enqueue a capture job keyed to the listing ID and the URL version. This helps avoid duplicate work when a listing is submitted or edited more than once.
- Capture a fixed viewport, or choose full-page capture where below-the-fold content is useful. Playwright supports viewport, full-page, element, and in-memory screenshots. Playwright screenshot guide
- Write the image to object storage or a CDN using a stable listing key, and save its key and capture time in the listing record. A directory workflow that captures, stores, serves, and periodically refreshes images is described by ScreenshotAPI’s directory guide.
- Show the image alongside the startup name and description. Keep a fallback image available and preserve the last successful preview if a new capture fails.
- Refresh after a URL change or on a scheduled cadence. Avoid recapturing on every directory page view.
Track at least the listing ID, normalized URL, image storage key, capture timestamp, capture status, and failure reason. This makes it possible to distinguish a missing preview from a stale one and to retry failures without affecting the listing itself.
2. Choose viewport, format, and capture mode
Use the same viewport dimensions for all directory cards so their framing is predictable. There is no universal thumbnail size: choose one that fits your design, then test it against representative desktop and mobile sites. OpenGraph.io documents presets such as 375 × 812, 1024 × 768, 1366 × 768, and 1920 × 1080; these are vendor presets, not a standard. OpenGraph.io capture documentation
| Choice | Good fit | Tradeoff |
|---|---|---|
| Viewport screenshot | Compact listing cards where the first screen is most recognizable. | Content below the fold is omitted. |
| Full-page screenshot | Detail pages where visitors benefit from seeing the whole landing page. | Very tall pages can shrink into an unreadable card image. |
| Element screenshot | A known page region, such as a hero area, is the desired preview. | The selector may not exist on every site. |
| PNG | Lossless output or sharp text edges matter. | Can produce larger files than lossy formats. |
| JPEG or WebP | Smaller card images are preferable. | Compression can soften text and fine detail. |
Playwright documents output format, quality, scale, and injected styles. Page.screenshot API A fixed viewport and output policy help keep generated assets consistent. Consider whether a card should crop to a fixed aspect ratio at display time or preserve the capture’s proportions.
3. Capture with Playwright in Node.js
The following example uses Playwright’s Chromium browser to capture a viewport screenshot and write it to a file. Install Playwright and its browser first with npm install playwright and npx playwright install chromium. In a production directory, call the capture logic from a background worker and upload the resulting buffer to your object storage.
import { chromium } from 'playwright';
import { writeFile } from 'node:fs/promises';
const target = new URL(process.env.SITE_URL ?? 'https://example.com');
if (!['http:', 'https:'].includes(target.protocol)) {
throw new Error('Only http and https URLs are supported');
}
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage({
viewport: { width: 1366, height: 768 },
deviceScaleFactor: 1,
});
const response = await page.goto(target.href, {
waitUntil: 'domcontentloaded',
timeout: 30000,
});
if (!response || !response.ok()) {
throw new Error(`Navigation failed: ${response?.status() ?? 'no response'}`);
}
await page.screenshot({ path: 'startup-preview.webp', type: 'webp' });
} finally {
await browser.close();
}
The example intentionally waits for domcontentloaded, which can avoid waiting indefinitely for pages with ongoing network activity. For pages that render their main content later, wait for a specific selector or add a bounded delay before capture. Set a timeout and keep failure handling around each job; a third-party site is outside your control.
Capture an element or a full page
// Full-page capture
await page.screenshot({ path: 'startup-full.webp', type: 'webp', fullPage: true });
// Capture one element (throws if the selector cannot be found)
const hero = page.locator('main');
await hero.screenshot({ path: 'startup-hero.png', type: 'png' });
Use full-page capture selectively. The image can become too tall to read at card size. An element selector such as main is not guaranteed to identify the same meaningful region across unrelated sites; handle missing selectors by falling back to the viewport screenshot.
4. Use a hosted screenshot API
A hosted API moves browser installation and rendering operations to a service. Your directory still needs a policy for URL validation, storage, refresh timing, retries, and how long to retain captures. Screenshot API parameters vary by provider, so confirm current behavior, pricing, quotas, regional availability, retention, and terms before committing. For example, OpenGraph.io documents dimensions, viewport presets, delay, and a cookie-banner option; those controls are specific to its service. OpenGraph.io documentation
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. A single GET request can return a PNG, JPEG, WebP, or PDF, and its options include viewport and full-page capture, element selection, custom CSS and JavaScript, wait conditions, caching, and more. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Cookie banners are accepted and removed before capture, along with 60+ known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers indicate the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Learn about ScreenshotNeo.
Sign up for 1,000 free screenshots a month with no card.
5. Consider Open Graph images as a separate preview source
An Open Graph image is publisher-provided metadata, not a live screenshot. The Open Graph protocol defines metadata for representing page objects, including image data. Open Graph protocol Reading this metadata may be cheaper than rendering a page, but inspect whether the declared image actually helps users recognize the startup’s current site. ScreenshotAPI’s guide notes that some sites have no og:image and some declared images are promotional rather than interface previews; treat that as vendor guidance, not an independent prevalence study. ScreenshotAPI directory guide
You can choose a fallback order: use a live screenshot when available, optionally use an inspected Open Graph image, then show a neutral placeholder. Store the source type so your team can understand why a card shows a particular image.
6. Refreshing, caching, and storage
- Stable keys: derive the object key from the listing ID and a version or content hash. Avoid a key based only on the submitted URL if URLs can change.
- Refresh triggers: recapture after a URL edit and periodically for unchanged listings. A scheduled refresh is documented in ScreenshotAPI’s directory workflow.
- Keep last success: upload a new successful result before updating the listing’s active image pointer. A failed refresh should not erase a useful prior image.
- Deduplicate work: collapse concurrent jobs for the same listing and URL version. This is an operational recommendation, not a vendor-specific feature claim.
- Serve through a CDN: cache image delivery separately from capture. This keeps directory page requests from triggering browser work.
- Set retention intentionally: remove obsolete versions according to your product’s storage and policy needs.
If using a hosted service’s cache, understand its cache key and lifetime. ScreenshotNeo supports caching with a TTL you choose, but the directory should still decide how its own stored asset is versioned and refreshed.
7. Reliability, performance, and cost
Capture latency depends on the destination site, page complexity, wait strategy, and browser work. The reviewed sources provide no comparable performance benchmark, so measure your own queue wait, capture duration, output size, and failure rate across representative sites before setting service targets.
- Keep submissions responsive: return the listing submission result before screenshot work finishes.
- Bound work: set navigation and job timeouts, cap concurrency, and retry transient failures with a limit.
- Avoid redundant capture: cache or reuse the last image until a relevant change or refresh deadline.
- Control output bytes: use an appropriate viewport and compressed format for card delivery; inspect legibility as well as file size.
- Preserve availability: render a fallback while the first capture is pending and keep the previous image if a refresh fails.
With Playwright, the tradeoff is operational ownership: your team runs the browser runtime, workers, storage, and refresh scheduling. A hosted API manages browser capture, while you still own the directory’s storage and product behavior. The dossier did not compare costs for self-hosting or other vendors. For ScreenshotNeo, the stated plans are Free: 1,000 shots/month; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. Confirm current plan details before purchase.
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Navigation timeout | The site is slow, unresponsive, or keeps network requests open. | Use a bounded timeout, try domcontentloaded, and retry only within a limit. Keep the prior preview. |
| Screenshot is blank or incomplete | The page renders content after the chosen readiness event or requires interaction. | Wait for a meaningful selector or a short bounded delay; inspect the page before capture. |
| Element selector not found | The target site uses a different layout or selector. | Fall back to viewport capture, or use per-site selectors only where you can maintain them. |
| Preview crops the important content | Viewport framing or card aspect ratio does not suit that site. | Adjust the shared viewport or card crop; test on a representative site set. |
| Full-page image is unreadable in the card | The page is much taller than the card. | Use viewport capture for cards and reserve full-page images for a detail view. |
| Refresh replaces a good image with a failure | The active storage pointer is updated before a new capture succeeds. | Upload first, then atomically switch the active key only after success. |
| Too many browser jobs run at once | Submissions trigger unbounded capture concurrency. | Queue jobs, cap worker concurrency, and deduplicate by listing and URL version. |
| Hosted API result is unexpected | Parameter behavior, plan limits, or output defaults differ by provider. | Check that provider’s current documentation and inspect the returned status and headers where available. |
9. Checklist before launch
- Choose a consistent viewport, format, and card treatment.
- Capture in a background job with bounded timeouts and retries.
- Validate submitted URLs and apply your own server-side destination protections.
- Store image keys and capture timestamps; retain the last successful image.
- Provide a placeholder for pending or never-successful captures.
- Refresh on URL changes and on a deliberate schedule.
- Measure capture duration, failure rate, and output size on your actual target sites.
- Review privacy, security, copyright, retention, and any India-specific obligations with appropriate expertise; the cited technical sources do not settle them.
10. FAQ
Should every listing use a full-page screenshot?
No. A fixed viewport is usually easier to read in a compact card. Use full-page capture when the extra page content helps in a larger preview context.
Can an Open Graph image replace a screenshot?
Sometimes, but it is publisher-supplied metadata and may be absent or promotional. Inspect it if you use it as a fallback or alternative.
Does the directory need to regenerate previews on every visit?
No. Store generated images and serve them as static assets; refresh them after changes or on a schedule.
Which browser engines can Playwright use?
Playwright’s official documentation covers Chromium, Firefox, and WebKit. Browser choice and installed runtime are part of your deployment setup. Playwright browsers documentation


