@power-seo/preview
v1.0.12
Published
SERP, Open Graph, and Twitter Card preview generators with React components
Maintainers
Readme
@power-seo/preview
Pixel-accurate SERP, Open Graph, and Twitter/X Card preview generators for TypeScript — compute exactly how a page appears in Google search results and social shares without a headless browser or canvas.
@power-seo/preview delivers pixel-width-aware SERP snippet generation, Open Graph image validation, and Twitter/X Card preview data — comparable to what Yoast SEO, Semrush, and Moz Pro show in their browser-based UIs, but as a standalone TypeScript library that runs anywhere. Provide a title, meta description, URL, and optional OG image — get back structured preview data with truncation flags, breadcrumb paths, and image validation results. Run it server-side in a CMS pipeline, client-side in a React editor, or inside a CI content gate. All four generators are fully tree-shakeable.
Zero runtime dependencies — only
@power-seo/coreas a peer.
Why @power-seo/preview?
| | Without | With |
| --------------------------- | ----------------------------------- | ----------------------------------------------------------------------- |
| SERP title truncation | ❌ Guesswork (character count) | ✅ Pixel-accurate truncation at 580px |
| SERP description truncation | ❌ Unchecked | ✅ Pixel-accurate truncation at 920px |
| OG image validation | ❌ Silent drop by Facebook/LinkedIn | ✅ Dimension check with pass/fail message |
| Twitter/X Card preview | ❌ Manual spec lookup | ✅ summary + summary_large_image with image validation |
| breadcrumb path | ❌ Unknown | ✅ Google-style example.com › blog › post format |
| React preview components | ❌ Build from scratch | ✅ Drop-in SerpPreview, OgPreview, TwitterPreview, PreviewPanel |
| Framework support | ❌ Browser tools only | ✅ Next.js, Remix, Node.js, Edge, any JS environment |
Features
- Pixel-accurate SERP truncation —
generateSerpPreview()truncates title at 580px, description at 920px using character-width lookup tables - Site title composition — optional
siteTitlefield appended as"title - siteTitle"before truncation, matching Google's display format - Google breadcrumb URL — formats
https://example.com/blog/my-postasexample.com › blog › my-post - Open Graph image validation —
generateOgPreview()validates image dimensions against the recommended 1200×630 minimum and reports pass/fail with a message - Twitter/X Card support —
generateTwitterPreview()handlessummaryandsummary_large_imagecard types with per-type image dimension requirements - Low-level truncation primitive —
truncateAtPixelWidth()truncates any string at any pixel budget, usable independently of the preview generators - Structured typed output — returns plain data objects ready for any UI renderer; no HTML, no DOM required
- React UI components — pre-built
SerpPreview,OgPreview,TwitterPreview, andPreviewPanelfrom the/reactsubpath - Framework-agnostic — works in Next.js, Remix, Gatsby, Vite, vanilla Node.js, Edge
- Full TypeScript support — complete type definitions for all inputs, outputs, and validation results
- Tree-shakeable — import only the generators you use;
"sideEffects": false - Zero runtime dependencies — pure computation, no canvas, no browser, no external libraries
Comparison
| Feature | @power-seo/preview | Yoast SEO | next-seo | react-helmet | seo-analyzer | | --------------------------------- | :----------------: | :---------------: | :------: | :----------: | :----------: | | Pixel-accurate SERP truncation | ✅ | ✅ (browser only) | ❌ | ❌ | ❌ | | SERP description truncation | ✅ | ✅ (browser only) | ❌ | ❌ | ❌ | | Google breadcrumb URL format | ✅ | ✅ | ❌ | ❌ | ❌ | | Open Graph image validation | ✅ | ❌ | ❌ | ❌ | ❌ | | Twitter/X Card preview generation | ✅ | ❌ | ❌ | ❌ | ❌ | | React preview components | ✅ | ✅ | ❌ | ❌ | ❌ | | Works outside WordPress | ✅ | ❌ | ✅ | ✅ | ✅ | | Edge runtime safe | ✅ | ❌ | ✅ | ✅ | ❌ | | Structured data output (not HTML) | ✅ | ❌ | ❌ | ❌ | ❌ | | TypeScript-first | ✅ | ❌ | Partial | ❌ | ❌ | | Tree-shakeable | ✅ | ❌ | Partial | ❌ | ❌ | | CI / Node.js usage | ✅ | ❌ | ❌ | ❌ | ✅ | | Zero runtime dependencies | ✅ | ❌ | ❌ | ❌ | ❌ |
Installation
npm install @power-seo/previewyarn add @power-seo/previewpnpm add @power-seo/previewQuick Start
import { generateSerpPreview, generateOgPreview } from '@power-seo/preview';
const serp = generateSerpPreview({
title: 'How to Add SEO to React Apps',
description: 'Learn how to add meta tags, Open Graph, and JSON-LD to any React application.',
url: 'https://example.com/blog/react-seo',
siteTitle: 'My Blog', // optional — appended as "title - siteTitle"
});
console.log(serp.title); // 'How to Add SEO to React Apps - My Blog' (truncated at 580px if too long)
console.log(serp.displayUrl); // 'example.com › blog › react-seo'
console.log(serp.titleTruncated); // false
const og = generateOgPreview({
title: 'React SEO Guide',
description: 'Complete SEO for React',
url: 'https://example.com/blog/react-seo',
image: { url: 'https://example.com/og.jpg', width: 1200, height: 630 },
});
console.log(og.image?.valid); // true
console.log(og.image?.message); // undefined (dimensions are correct)Usage
Generating a Google SERP Preview
generateSerpPreview() computes the display title, breadcrumb URL, and description that Google would show, with pixel-accurate truncation flags.
import { generateSerpPreview } from '@power-seo/preview';
const serp = generateSerpPreview({
title: 'Next.js SEO Best Practices',
description:
'Learn how to optimize your Next.js app for search engines with meta tags and structured data.',
url: 'https://example.com/nextjs-seo',
siteTitle: 'Dev Blog', // optional
});
// serp.title → 'Next.js SEO Best Practices - Dev Blog' (possibly truncated)
// serp.displayUrl → 'example.com › nextjs-seo'
// serp.description → display description (possibly truncated at 920px)
// serp.titleTruncated → true | false
// serp.titleValidation → ValidationResult from @power-seo/coreGenerating an Open Graph Preview
generateOgPreview() validates image dimensions and returns a structured card data object for Facebook, LinkedIn, and other OG-compatible platforms.
import { generateOgPreview } from '@power-seo/preview';
const og = generateOgPreview({
title: 'React SEO Guide',
description: 'Complete guide to adding SEO in React apps.',
url: 'https://example.com/react-seo',
siteName: 'Dev Blog',
image: { url: 'https://example.com/og.jpg', width: 800, height: 400 },
});
// og.image?.valid → false (too small)
// og.image?.message → 'Image is 800x400px. Minimum size is 200x200px.'Generating a Twitter/X Card Preview
generateTwitterPreview() handles both summary and summary_large_image card types, each with different image dimension requirements.
import { generateTwitterPreview } from '@power-seo/preview';
const twitter = generateTwitterPreview({
cardType: 'summary_large_image',
title: 'React SEO Guide',
description: 'Everything you need to add SEO to any React application.',
url: 'https://example.com/react-seo',
site: '@myblog',
image: { url: 'https://example.com/twitter.jpg', width: 1200, height: 628 },
});
// twitter.cardType → 'summary_large_image'
// twitter.domain → 'myblog'
// twitter.image?.valid → trueUsing the Low-Level Truncation Primitive
truncateAtPixelWidth() is a standalone utility — use it to truncate any string at any pixel budget, independent of the SERP generator.
import { truncateAtPixelWidth } from '@power-seo/preview';
const result = truncateAtPixelWidth(
'Buy Premium Running Shoes Online — Free Shipping Worldwide',
580,
);
// result.text → 'Buy Premium Running Shoes Online — Free Shippi...'
// result.truncated → trueReact Components
Import from the /react entry point for pre-built preview UI components:
import { SerpPreview, OgPreview, TwitterPreview, PreviewPanel } from '@power-seo/preview/react';
// All-in-one tabbed panel (Google / Facebook / Twitter)
function EditorSidebar() {
return (
<PreviewPanel
title="How to Add SEO to React Apps"
description="Learn meta tags, Open Graph, and JSON-LD for React."
url="https://example.com/blog/react-seo"
siteTitle="My Blog"
siteName="My Blog"
image={{ url: 'https://example.com/og.jpg', width: 1200, height: 630 }}
twitterCardType="summary_large_image"
twitterSite="@myblog"
/>
);
}
// Or use individual components
function SerpCard() {
return (
<SerpPreview
title="How to Add SEO to React Apps"
description="Learn meta tags, Open Graph, and JSON-LD for React."
url="https://example.com/blog/react-seo"
siteTitle="My Blog"
/>
);
}Inside a CI Content Quality Gate
Block deploys when SERP titles or OG images fail validation:
import { generateSerpPreview, generateOgPreview } from '@power-seo/preview';
const serp = generateSerpPreview({ title, description, url, siteTitle });
const og = generateOgPreview({ title, description, url, image });
if (serp.titleTruncated) {
console.error('SERP title exceeds 580px — will be cut off in Google results');
process.exit(1);
}
if (og.image && !og.image.valid) {
console.error('OG image invalid:', og.image.message);
process.exit(1);
}API Reference
Entry Points
| Import | Description |
| -------------------------- | ---------------------------------------------- |
| @power-seo/preview | Core preview generators and truncation utility |
| @power-seo/preview/react | React components for preview UI |
generateSerpPreview()
function generateSerpPreview(input: SerpPreviewInput): SerpPreviewData;SerpPreviewInput
| Prop | Type | Required | Description |
| ------------- | -------- | -------- | --------------------------------------------------------------- |
| title | string | ✅ | Page title |
| description | string | ✅ | Meta description |
| url | string | ✅ | Canonical page URL |
| siteTitle | string | — | Site name — appended as "title - siteTitle" before truncation |
SerpPreviewData
| Output Field | Type | Description |
| ----------------------- | ------------------ | -------------------------------------------------- |
| title | string | Display title (truncated at 580px if needed) |
| displayUrl | string | Breadcrumb path (e.g. example.com › blog › post) |
| description | string | Display description (truncated at 920px if needed) |
| titleTruncated | boolean | Whether title was truncated |
| descriptionTruncated | boolean | Whether description was truncated |
| titleValidation | ValidationResult | Title length/pixel validation result |
| descriptionValidation | ValidationResult | Description length/pixel validation result |
generateOgPreview()
function generateOgPreview(input: OgPreviewInput): OgPreviewData;OgPreviewInput
| Prop | Type | Required | Description |
| ------------- | -------------------------------------------------- | -------- | ------------------------------- |
| title | string | ✅ | OG title |
| description | string | ✅ | OG description |
| url | string | ✅ | Canonical URL |
| image | { url: string; width?: number; height?: number } | — | OG image (recommended 1200×630) |
| siteName | string | — | Site name displayed on the card |
OgPreviewData
| Output Field | Type | Description |
| ------------- | -------------------------------- | ---------------------------------------- |
| title | string | OG title |
| description | string | OG description |
| url | string | Canonical URL |
| siteName | string \| undefined | Site name |
| image | OgImageValidation \| undefined | Image with validation result (see below) |
OgImageValidation
| Field | Type | Description |
| --------- | --------------------- | --------------------------------------------------------- |
| url | string | Image URL |
| width | number \| undefined | Image width in pixels |
| height | number \| undefined | Image height in pixels |
| valid | boolean | Whether the image meets OG dimension requirements |
| message | string \| undefined | Human-readable validation message when dimensions deviate |
generateTwitterPreview()
function generateTwitterPreview(input: TwitterPreviewInput): TwitterPreviewData;TwitterPreviewInput
| Prop | Type | Required | Description |
| ------------- | -------------------------------------------------- | -------- | ------------------------------------------------ |
| cardType | 'summary' \| 'summary_large_image' | ✅ | Twitter Card type |
| title | string | ✅ | Card title |
| description | string | ✅ | Card description |
| image | { url: string; width?: number; height?: number } | — | Card image |
| site | string | — | Twitter @username of the site (e.g. '@myblog') |
TwitterPreviewData
| Output Field | Type | Description |
| ------------- | ------------------------------------- | ------------------------------------------------------ |
| cardType | TwitterCardType | The card type ('summary' or 'summary_large_image') |
| title | string | Card title |
| description | string | Card description |
| image | TwitterImageValidation \| undefined | Image with validation result |
| domain | string \| undefined | Extracted domain from site handle |
TwitterImageValidation
| Field | Type | Description |
| --------- | --------------------- | -------------------------------------------------------------------------------- |
| url | string | Image URL |
| width | number \| undefined | Image width in pixels |
| height | number \| undefined | Image height in pixels |
| valid | boolean | Whether the image meets Twitter Card dimension requirements |
| message | string \| undefined | Human-readable validation message when dimensions deviate from recommended sizes |
truncateAtPixelWidth()
function truncateAtPixelWidth(text: string, maxPixels: number): TruncateResult;TruncateResult
| Output Field | Type | Description |
| ------------ | --------- | ------------------------------------- |
| text | string | Resulting (possibly truncated) string |
| truncated | boolean | Whether truncation occurred |
React Components
Import all components from @power-seo/preview/react.
import { SerpPreview, OgPreview, TwitterPreview, PreviewPanel } from '@power-seo/preview/react';SerpPreview
Renders a Google-style SERP result card.
| Prop | Type | Required | Description |
| ------------- | -------- | -------- | ------------------------------------------------------ |
| title | string | ✅ | Page title |
| description | string | ✅ | Meta description |
| url | string | ✅ | Canonical URL |
| siteTitle | string | — | Site name — appended to title as "title - siteTitle" |
OgPreview
Renders a Facebook/Open Graph card mockup.
| Prop | Type | Required | Description |
| ------------- | -------------------------------------------------- | -------- | ------------------------------- |
| title | string | ✅ | OG title |
| description | string | ✅ | OG description |
| url | string | ✅ | Canonical URL |
| image | { url: string; width?: number; height?: number } | — | OG image |
| siteName | string | — | Site name shown above the title |
TwitterPreview
Renders a Twitter/X card mockup for summary or summary_large_image card types.
| Prop | Type | Required | Description |
| ------------- | -------------------------------------------------- | -------- | -------------------------------------- |
| cardType | TwitterCardType | ✅ | 'summary' or 'summary_large_image' |
| title | string | ✅ | Card title |
| description | string | ✅ | Card description |
| image | { url: string; width?: number; height?: number } | — | Card image |
| site | string | — | Twitter @username of the site |
PreviewPanel
Tabbed container with Google, Facebook, and Twitter/X preview cards in a single component.
| Prop | Type | Required | Description |
| ----------------- | -------------------------------------------------- | -------- | ---------------------------------------------------- |
| title | string | ✅ | Page title |
| description | string | ✅ | Meta description |
| url | string | ✅ | Canonical URL |
| image | { url: string; width?: number; height?: number } | — | Shared image for OG and Twitter cards |
| siteName | string | — | OG site name |
| siteTitle | string | — | SERP site name (appended to title) |
| twitterSite | string | — | Twitter @username |
| twitterCardType | TwitterCardType | — | Twitter Card type (default: 'summary_large_image') |
Types
| Type | Description |
| ------------------------ | ------------------------------------------------------------- |
| SerpPreviewInput | Input shape for generateSerpPreview() |
| SerpPreviewData | Output shape from generateSerpPreview() |
| OgPreviewInput | Input shape for generateOgPreview() |
| OgPreviewData | Output shape from generateOgPreview() |
| OgImageValidation | Image validation result on OgPreviewData.image |
| TwitterPreviewInput | Input shape for generateTwitterPreview() |
| TwitterPreviewData | Output shape from generateTwitterPreview() |
| TwitterImageValidation | Image validation result on TwitterPreviewData.image |
| TruncateResult | Output shape from truncateAtPixelWidth() |
| TwitterCardType | 'summary' \| 'summary_large_image' (from @power-seo/core) |
| ValidationResult | Title/description validation result (from @power-seo/core) |
Use Cases
- CMS live preview panels — show authors how their title and description appear in Google before publishing
- SEO auditing pipelines — detect truncated titles and invalid OG images at build time
- Programmatic SEO sites — validate auto-generated titles for thousands of pages at once
- Social media schedulers — validate OG image dimensions before queuing posts
- SaaS marketing dashboards — show SERP and social card previews for every page
- Blog platforms — live preview as editors type the meta description
- eCommerce product pages — ensure product image dimensions meet OG card requirements
- Landing page builders — embed SERP and social card previews in the editor UI
- CI content quality gates — fail builds when SERP titles are truncated or OG images are too small
Architecture Overview
- Pure TypeScript — no compiled binary, no native modules
- Zero runtime dependencies — only
@power-seo/coreas a peer dependency - Character-width lookup — pixel truncation uses per-character width tables matching Google's SERP font metrics, not character counts
- Framework-agnostic — works in any JavaScript environment
- SSR compatible — safe to run in Next.js Server Components, Remix loaders, or Express handlers
- Edge runtime safe — no Node.js-specific APIs; no
fs, nocanvas; runs in Cloudflare Workers, Vercel Edge, Deno - Tree-shakeable —
"sideEffects": falsewith named exports per generator function - Dual ESM + CJS — ships both formats via tsup for any bundler or
require()usage - React optional — React is a peer dependency; the
/reactsubpath is only included when React is present
Supply Chain Security
- No install scripts (
postinstall,preinstall) - No runtime network access
- No
evalor dynamic code execution - CI-signed builds — all releases published via verified
github.com/CyberCraftBD/power-seoworkflow - Safe for SSR, Edge, and server environments
The @power-seo Ecosystem
All 17 packages are independently installable — use only what you need.
| Package | Install | Description |
| ------------------------------------------------------------------------------------------ | ----------------------------------- | ----------------------------------------------------------------------- |
| @power-seo/core | npm i @power-seo/core | Framework-agnostic utilities, types, validators, and constants |
| @power-seo/react | npm i @power-seo/react | React SEO components — meta, Open Graph, Twitter Card, breadcrumbs |
| @power-seo/meta | npm i @power-seo/meta | SSR meta helpers for Next.js App Router, Remix v2, and generic SSR |
| @power-seo/schema | npm i @power-seo/schema | Type-safe JSON-LD structured data — 23 builders + 22 React components |
| @power-seo/content-analysis | npm i @power-seo/content-analysis | Yoast-style SEO content scoring engine with React components |
| @power-seo/readability | npm i @power-seo/readability | Readability scoring — Flesch-Kincaid, Gunning Fog, Coleman-Liau, ARI |
| @power-seo/preview | npm i @power-seo/preview | SERP, Open Graph, and Twitter/X Card preview generators |
| @power-seo/sitemap | npm i @power-seo/sitemap | XML sitemap generation, streaming, index splitting, and validation |
| @power-seo/redirects | npm i @power-seo/redirects | Redirect engine with Next.js, Remix, and Express adapters |
| @power-seo/links | npm i @power-seo/links | Link graph analysis — orphan detection, suggestions, equity scoring |
| @power-seo/audit | npm i @power-seo/audit | Full SEO audit engine — meta, content, structure, performance rules |
| @power-seo/images | npm i @power-seo/images | Image SEO — alt text, lazy loading, format analysis, image sitemaps |
| @power-seo/ai | npm i @power-seo/ai | LLM-agnostic AI prompt templates and parsers for SEO tasks |
| @power-seo/analytics | npm i @power-seo/analytics | Merge GSC + audit data, trend analysis, ranking insights, dashboard |
| @power-seo/search-console | npm i @power-seo/search-console | Google Search Console API — OAuth2, service account, URL inspection |
| @power-seo/integrations | npm i @power-seo/integrations | Semrush and Ahrefs API clients with rate limiting and pagination |
| @power-seo/tracking | npm i @power-seo/tracking | GA4, Clarity, PostHog, Plausible, Fathom — scripts + consent management |
About CyberCraft Bangladesh
CyberCraft Bangladesh is a Bangladesh-based enterprise-grade software development and Full Stack SEO service provider company specializing in ERP system development, AI-powered SaaS and business applications, full-stack SEO services, custom website development, and scalable eCommerce platforms. We design and develop intelligent, automation-driven SaaS and enterprise solutions that help startups, SMEs, NGOs, educational institutes, and large organizations streamline operations, enhance digital visibility, and accelerate growth through modern cloud-native technologies.
© 2026 CyberCraft Bangladesh · Released under the MIT License
