How to Generate Website Preview Thumbnails for Indian Real Estate Listings
Generate clear property listing thumbnails, serve responsive image variants, and set page metadata for social sharing and search without assuming one India-wide size.
Generate thumbnails from genuine, authorized photos of the listed property. Make image variants for the layouts your site actually uses, embed them as HTML images, and set a representative preview image in metadata on each listing page. There is no source-backed universal thumbnail size for Indian real estate sites, and Google chooses its search image automatically, so treat your crop and metadata as guidance rather than a guarantee.
This guide builds a small thumbnail pipeline with Node.js and Sharp, shows how to serve the result responsively, and covers social and Google-facing metadata. It also explains when a screenshot of a listing page is useful and how ScreenshotNeo can produce one without you managing a browser.
1. Choose the image and display contexts
Start with an image you have permission to use and that accurately represents the property. Keep the original as the source of truth; create derived files for the site rather than overwriting the original. PropertyHub India’s own media policy requires genuine, clear, unaltered, non-misleading property media. That is a platform-specific policy, not a nationwide rule. See PropertyHub’s photo and document upload guidelines.
Inventory where each image appears before choosing dimensions. A listing card, a property detail gallery, and a shared-link preview may have different aspect ratios and quality needs. No universal India-specific pixel size was established by the sources reviewed. Choose output dimensions to fit your own layouts, and inspect the crop at its actual rendered size.
| Use | Implementation choice | Check |
|---|---|---|
| Listing card | A consistent aspect ratio and crop can make a grid orderly. Use a flexible ratio if cutting off property context would mislead. | Inspect the smallest card and confirm the recognizable part of the property remains visible. |
| Detail page | Serve a larger derivative or the original, with responsive variants where useful. | Confirm the image remains clear on the largest supported layout. |
| Social link preview | Set a representative absolute image URL in og:image for each listing page. |
Check the image URL and metadata from outside an authenticated session. |
| Google image discovery | Use a standard HTML image element with a crawlable image URL. An image sitemap can expose images that might otherwise be missed. | Ensure crawlers can fetch the page and image. |
Fixed cropping is useful when card consistency matters; flexible aspect ratios help preserve more of a property view. Neither is universally right. Pick the behavior deliberately and avoid edits that make the property appear materially different from the source photo.
2. Generate card and preview derivatives with Node.js
This runnable example reads one source image and writes two WebP derivatives. The dimensions below are example layout choices, not an Indian standard. Sharp’s cover fit fills the requested box and crops overflow; inside fits the whole image within the box without cropping. Choose the one that matches the content and layout.
mkdir listing-thumbnails
cd listing-thumbnails
npm init -y
npm install sharp
Save an authorized source image as property-original.jpg, then save the following as generate.mjs:
import sharp from 'sharp';
import { mkdir } from 'node:fs/promises';
const input = process.argv[2] ?? 'property-original.jpg';
const outputDir = process.argv[3] ?? 'public/property-123';
await mkdir(outputDir, { recursive: true });
// Example output dimensions: change these to match your actual components.
const variants = [
{ name: 'card-640.webp', width: 640, height: 400, fit: 'cover' },
{ name: 'share-1200.webp', width: 1200, height: 800, fit: 'inside' },
];
for (const variant of variants) {
await sharp(input)
.rotate() // Apply orientation from image metadata, when present.
.resize(variant.width, variant.height, {
fit: variant.fit,
withoutEnlargement: true,
background: { r: 255, g: 255, b: 255, alpha: 1 },
})
.webp({ quality: 82 })
.toFile(`${outputDir}/${variant.name}`);
console.log(`Created ${outputDir}/${variant.name}`);
}
Run it with node generate.mjs property-original.jpg public/property-123. The output path should map to a public URL on your site or image host, for example https://example.com/property-123/card-640.webp. Replace example domains and property IDs with your own. Keep output URLs stable or update references when regenerating assets.
Crop rules and image handling
cover: fills the output box and crops edges. Use it for uniform cards only after checking the crop keeps the property context clear.inside: keeps the entire image within the requested bounds and may leave unused space. Choose a background color appropriate for your page.- Orientation: phone photos can carry orientation metadata. The example applies it before resizing.
- Upscaling:
withoutEnlargementavoids enlarging a small source into a larger output. A larger file cannot restore missing detail. - Format: WebP is used in this example. Choose formats supported by your delivery requirements and verify them in target browsers and crawlers.
- Focal point: if important content is consistently off-center, add a per-image focal point strategy in your pipeline rather than applying a crop that hides it.
3. Serve variants in the listing page
Use ordinary HTML image markup so the image is represented as content, not only as a CSS background. Google says it does not index CSS images in the same way and recommends making images discoverable through HTML image elements. Its guidance also covers responsive images. Google’s image SEO best practices.
<article class="property-card">
<a href="/listings/property-123">
<img
src="https://example.com/property-123/card-640.webp"
srcset="https://example.com/property-123/card-320.webp 320w,
https://example.com/property-123/card-640.webp 640w"
sizes="(max-width: 600px) 100vw, 33vw"
width="640"
height="400"
alt="Front exterior of the listed apartment building in Pune"
loading="lazy"
decoding="async"
>
<h2>Two-bedroom apartment in Pune</h2>
</a>
</article>
Replace the example description with a concise description of what is visible in each actual image. If the image is purely decorative and conveys no information beyond adjacent text, an empty alt value may be more appropriate. Match width and height to the source variant’s actual dimensions; this lets the browser reserve space and reduces layout movement. Use lazy loading for images below the initial viewport, but consider loading the leading image eagerly if it is visible immediately.
The srcset candidates and sizes value should reflect the files you generate and the width the component occupies. If the card takes the full mobile viewport and about one third of a wide page, the example is a starting point; verify it against your layout. Responsive delivery is a selection mechanism, not an image-generation step: make sure each referenced variant exists.
4. Set link-preview metadata for each listing
Open Graph defines og:image and optional image properties including type, dimensions, and alt description. Add the tags to the rendered HTML head of each listing page, with absolute, publicly fetchable URLs. Open Graph protocol.
<meta property="og:title" content="Two-bedroom apartment in Pune">
<meta property="og:type" content="website">
<meta property="og:url" content="https://example.com/listings/property-123">
<meta property="og:image" content="https://example.com/property-123/share-1200.webp">
<meta property="og:image:type" content="image/webp">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="800">
<meta property="og:image:alt" content="Exterior view of the listed apartment building in Pune">
Set metadata per listing so a shared property URL points to that property’s representative image. The sample dimensions must match the actual generated file; adjust them if your variant is different. Social crawlers may cache fetched previews, so after changing an image or tag, recheck using the sharing platform’s available preview/debug tooling.
5. Help Google understand the preferred image
Google chooses image previews automatically. A representative image in page metadata or structured data can indicate your preference, but it does not guarantee that Google will use that image. Google documents primaryImageOfPage as one way to identify a preferred image. Google image guidance.
If you already publish JSON-LD for a listing, attach the image URL to the correct page or main entity and keep it consistent with visible content. For example, a page-level WebPage can identify a primary image:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"url": "https://example.com/listings/property-123",
"primaryImageOfPage": {
"@type": "ImageObject",
"contentUrl": "https://example.com/property-123/share-1200.webp"
}
}
</script>
This is an illustrative image reference, not a complete property listing schema. Use the appropriate schema type and properties for your actual page. Google’s structured data rules require image URLs to be crawlable and indexable, and valid markup only makes a page eligible for supported features; it does not guarantee display. Google’s structured data guidelines.
If important listing images are difficult to discover through page links, an image sitemap can provide additional discovery information. It complements crawlable pages and image URLs; it does not make a blocked or inaccessible image crawlable. Google’s image sitemap documentation.
6. Validate before publishing
- Inspect the source: confirm you have rights to use it and that it genuinely depicts the listing.
- Inspect every derivative: check orientation, crop, clarity, dimensions, and file format on both desktop and mobile layouts.
- Fetch the image URL directly: it should return the image to an unauthenticated visitor, with a correct image response and no temporary access token that expires before crawlers fetch it.
- Inspect rendered HTML: verify the listing has a standard image element, useful alt text, and the intended metadata in the page head.
- Check crawler access: ensure robots rules, access controls, or hotlink protection do not prevent Google from fetching the page or image.
- Use Google tools where applicable: inspect the page in Search Console and use supported result testing tools for the structured data you implement. These tools can reveal issues; they cannot force a particular preview.
- Check actual shares: use the target social destination’s preview tooling when available and account for cached metadata.
7. Generate a thumbnail from a rendered listing page
Image resizing and browser screenshots solve different problems. Use Sharp when you have the property’s source photo and need image derivatives. Use a browser capture when the desired output is a rendered card, listing page, or element that includes page layout and styles. A screenshot of a page is not automatically a good property photo or a replacement for a clean source image.
For a local browser workflow, an automation browser can load the listing page and capture an element or viewport. Keep the capture deterministic: wait for the relevant image to load, use a fixed viewport, and avoid capturing personalized or authenticated content unintentionally. This approach adds browser setup and page-load failure modes. If you only need variants of existing photographs, the Sharp pipeline above is simpler.
Or skip the browser setup
Use ScreenshotNeo to capture a rendered listing page as an image. It is a website screenshot API and MCP server from ScreenshotNeo. The call below captures a page; change the target to a publicly accessible listing URL. See the ScreenshotNeo API documentation for options such as element capture, viewport, image format, and waiting behavior.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/listings/property-123 -o listing.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com/listings/property-123"},
timeout=90,
)
r.raise_for_status()
open("listing.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com/listings/property-123'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(async ({ writeFile }) =>
writeFile('listing.webp', Buffer.from(await res.arrayBuffer()))
);
ScreenshotNeo removes known consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status. Its MCP server provides screenshot tools for AI agents. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000 screenshots. Use the free ScreenshotNeo sign-up to get started.
8. Performance, reliability, and cost
- Generate once when possible: pre-generate derivatives when a listing photo is uploaded or changed, rather than resizing the same original on every page request. This trades storage and a processing step for less repeated image work.
- Use the right variant: send a suitably sized source through responsive image markup so a small card does not needlessly fetch a much larger file. Confirm real file sizes and visual quality for your own photos; this article makes no benchmark claim.
- Cache stable outputs: version filenames or otherwise invalidate caches when an image changes. A stale image at a stable URL can persist in browser, CDN, and social preview caches.
- Handle pipeline failures: keep the original, log failed transformations, and retry or regenerate derivatives without publishing a broken URL. Do not silently substitute a different property’s image.
- Budget storage and processing: more variants consume more storage and require more generation work. Make variants only for actual layouts and avoid generating every possible size up front.
- Protect access and privacy: do not expose private listing images or sensitive page content through public image URLs or screenshots. Public crawlers and social preview fetchers generally need an accessible image to retrieve it.
- For screenshots: page loading, scripts, fonts, and third-party widgets affect whether the rendered result is useful. Use a direct image pipeline for source-photo thumbnails and a screenshot service for rendered-page captures.
9. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The card image is cropped badly | The chosen aspect ratio and cover crop do not suit the source photo. | Inspect the crop, use a focal point, change the ratio, or use a contain-style treatment when the whole view must remain visible. |
| The photo is sideways | Orientation metadata was not applied during processing. | Apply orientation before resize, as in the Sharp example, and inspect the resulting derivative. |
| A derivative looks blurry | The source is too small, the output is being enlarged, or the wrong variant is being selected. | Use a higher-resolution authorized source, avoid upscaling, and inspect the browser’s selected srcset candidate. |
| The image is missing in the browser | The URL is wrong, inaccessible, blocked, or the generated file was not deployed. | Request the exact URL directly, check deployment and access rules, and verify every referenced variant exists. |
| Google does not show the preferred image | Google selects previews automatically; the page or image may also be inaccessible or not yet recrawled. | Keep the image representative, crawlable, and consistent with page content; inspect the URL with Search Console. There is no markup guarantee. |
| A social share uses an old or wrong image | Metadata is missing, points to the wrong listing, or a platform is showing a cached preview. | Check the rendered head and absolute og:image URL, then use the destination’s preview refresh/debug tool if available. |
| Structured data image is ignored | The image URL cannot be crawled, markup does not match visible content, or the feature is not shown for that result. | Make the URL public to crawlers, correct the markup, and validate it with Google’s supported tools. Valid data does not guarantee display. |
| The screenshot is blank or contains a banner | The page did not finish loading, a bot check appeared, or cleanup behavior is disabled or unavailable for that page. | Check the target URL and wait conditions; adjust capture options. ScreenshotNeo identifies page verdict and billing in response headers. |
| Node reports that Sharp cannot process the file | The input is unsupported, corrupted, or the deployment environment lacks a compatible Sharp installation. | Confirm the source opens as an image, reinstall dependencies for the target runtime, and log the source path and processing error. |
10. Frequently asked questions
Will Google use my og:image as the search thumbnail?
It may help indicate a preferred image, but Google chooses automatically and does not guarantee a particular image.
Do I need structured data just to show a listing thumbnail?
No. Use a crawlable HTML image and accurate page metadata. Structured data can describe the page when appropriate, but it is not a display guarantee.
Should a listing card use the same image as the shared preview?
It can, if that crop represents the property well in both contexts. Separate derivatives are useful when the layouts need different aspect ratios or framing.
Can I use CSS background images for the main property photo?
Use an HTML image element for important property imagery that should be discoverable. CSS backgrounds can remain appropriate for decoration.
Is a screenshot a substitute for a property photograph?
Usually not. Capture a rendered page when you need a page or card preview; use an authorized source photo to create listing image derivatives.


