DEV Community

Daniel Rozin
Daniel Rozin

Posted on • Originally published at aversusb.net

White-Label Comparison Widgets: How We Turned Our Data Into an Embeddable Revenue Stream

Every comparison site sits on structured data that other businesses would pay to use. We turned ours into embeddable widgets that brands put on their own sites — and it became our fastest-growing revenue channel.

Here's how we built it, priced it, and what we learned selling it.

The Problem We Solved

Brands have a comparison problem. Their customers are searching "Brand X vs Brand Y" before buying, but brands can't control that narrative on third-party sites. They either:

  1. Ignore comparison searches entirely (most common)
  2. Create biased comparison pages on their own site (low trust)
  3. Hope third-party comparison sites are favorable (no control)

Our widget gives them option 4: embed a neutral, data-backed comparison directly on their product pages. The data comes from our platform. The presentation matches their brand. The customer stays on their site.

Architecture: How the Widget Works

The embed is a lightweight JavaScript snippet that loads comparison data from our API:

<div id="smartreview-compare" 
     data-entity-a="airpods-pro-2" 
     data-entity-b="sony-wf-1000xm5"
     data-theme="light"
     data-brand-color="#1a73e8">
</div>
<script src="https://widgets.aversusb.net/compare.js" async></script>
Enter fullscreen mode Exit fullscreen mode

The script does three things:

  1. Fetches comparison data from our CDN-cached API (avg 45ms response time)
  2. Renders a responsive comparison card using Shadow DOM (no CSS conflicts with host page)
  3. Tracks impressions and clicks for the brand's analytics dashboard

Why Shadow DOM Matters

Early versions used standard DOM injection. Every third brand had CSS conflicts — their reset stylesheets broke our layout, their font stacks overrode ours, their box-sizing rules shifted columns.

Shadow DOM encapsulates everything. The widget renders identically on a Shopify store, a WordPress blog, and a custom React app. Zero support tickets since we switched.

class CompareWidget extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  async connectedCallback() {
    const entityA = this.dataset.entityA;
    const entityB = this.dataset.entityB;
    const theme = this.dataset.theme || 'light';
    const brandColor = this.dataset.brandColor || '#2563eb';

    const data = await fetch(
      `https://api.aversusb.net/v1/compare/${entityA}/${entityB}`
    ).then(r => r.json());

    this.shadowRoot.innerHTML = this.render(data, theme, brandColor);
    this.trackImpression(entityA, entityB);
  }
}

customElements.define('smartreview-compare', CompareWidget);
Enter fullscreen mode Exit fullscreen mode

Performance Budget

The widget script is 8KB gzipped. We set this as a hard ceiling because every KB matters when you're asking brands to add third-party JavaScript to their product pages.

Breakdown:

  • Core rendering: 3.2KB
  • Data fetching + caching: 1.8KB
  • Analytics tracking: 1.1KB
  • Theme engine: 1.4KB
  • Error handling + fallback: 0.5KB

No framework dependencies. No external CSS. No web fonts. Pure vanilla JS with a compile step that tree-shakes aggressively.

Theming System

Brands won't embed anything that looks out of place. Our theming system accepts:

  • Brand color: Primary accent used for headers, highlights, CTAs
  • Theme: Light or dark mode
  • Layout: Horizontal (for product pages) or vertical (for sidebars)
  • Attributes: Which comparison dimensions to show (up to 8)
  • CTA: Custom button text and destination URL

The brand color propagates through the entire component using CSS custom properties inside the shadow root. One color input produces a full palette:

:host {
  --brand-primary: var(--sr-brand-color, #2563eb);
  --brand-light: color-mix(in srgb, var(--brand-primary) 15%, white);
  --brand-dark: color-mix(in srgb, var(--brand-primary) 85%, black);
  --brand-text: color-contrast(var(--brand-primary) vs white, black);
}
Enter fullscreen mode Exit fullscreen mode

This means a brand passes one hex code and gets a fully coordinated widget that looks native to their site.

Pricing Tiers

We tested three pricing models before landing on what works:

What Failed

Per-impression pricing ($0.001–$0.01 per view): Brands hated unpredictable costs. Enterprise procurement teams need fixed line items.

Annual contracts only: Too much commitment for a new widget category. Brands wanted to test before locking in.

What Works

Tiered monthly subscriptions based on comparison volume:

Tier Monthly Comparisons Features
Starter $500 Up to 10 product pairs Basic theming, standard support
Growth $1,000 Up to 50 product pairs Full theming, priority support, analytics dashboard
Enterprise $2,000+ Unlimited Custom attributes, API access, dedicated account manager, SLA

The key insight: brands don't think in impressions, they think in products. "How many products can I compare?" is the natural question. Tying pricing to comparison pairs made the value proposition intuitive.

The Free Tier That Drives Sales

We offer a free "powered by SmartReview" widget with 3 comparison pairs. It includes a small attribution link. About 15% of free users convert to Starter within 60 days, primarily to remove the attribution and add more products.

The free tier also serves as a lead generation tool — every widget impression on a brand's site is an implicit endorsement visible to their competitors.

The Sales Process

Our 4-touch outreach sequence for widget sales:

Touch 1: Send a mockup. Not a pitch — an actual screenshot of their product page with our widget embedded. We use a browser extension to inject the widget on their live site, screenshot it, and include it in the email. This converts at 3x any text-only pitch.

Touch 2: Share a competitive intelligence report showing how many "[their product] vs [competitor]" searches happen monthly. Frame the widget as capturing demand they're currently losing.

Touch 3: Case study from a similar brand in their category with specific metrics (impressions, time-on-page impact, conversion lift).

Touch 4: Direct ask with a time-limited offer (first month free, or category exclusivity for 90 days).

Analytics Dashboard

Growth and Enterprise tiers get a real-time dashboard showing:

  • Widget impressions by page and product pair
  • Click-through rate on comparison attributes
  • Most-viewed comparison dimensions (tells the brand what buyers care about)
  • Geographic distribution of widget viewers
  • Device breakdown (mobile vs desktop engagement patterns differ significantly)

The analytics data is often more valuable than the widget itself. Brands use it to inform product positioning, feature prioritization, and ad copy. One electronics brand told us: "We learned more about what buyers compare from your dashboard than from six months of focus groups."

Technical Lessons

Cache aggressively on the edge. Comparison data changes at most daily, but widgets load on every page view. We cache at the CDN layer with 1-hour TTL and purge on data updates. This dropped our API costs 94% and improved widget load time from 180ms to 45ms.

Provide a static fallback. If our API is down, the widget renders a cached snapshot from localStorage. Brands embedding third-party scripts need reliability guarantees — one outage that breaks their product page and you lose the account forever.

Version your embed script. We serve compare.js with a version parameter and maintain backwards compatibility for 6 months. Breaking changes get a new major version and a migration guide. One brand still runs v1 from 8 months ago and it works fine.

Respect Content Security Policy. Many enterprise sites have strict CSP headers. Our widget loads everything from a single domain (widgets.aversusb.net) and makes API calls to one endpoint (api.aversusb.net). No inline scripts, no eval, no dynamic imports from third-party domains.

Revenue Impact

After 4 months of active widget sales:

  • 8 paying brands across 3 tiers
  • 23 free-tier users (pipeline for conversion)
  • Widget revenue: ~$6,500/month recurring
  • Average contract value: $812/month
  • Churn: 0% (too early to be meaningful, but promising)

The surprise: widget customers also become our best affiliate partners. They already trust our data. Upgrading them from widget-only to widget + affiliate is a natural expansion conversation.

What's Next

We're building three things:

  1. A/B testing for widget layouts — let brands test which comparison attributes drive the most engagement on their pages
  2. Shopify app — one-click install instead of manual embed, targeting the long tail of DTC brands
  3. Real-time pricing data in widgets — showing live price comparisons within the embedded component

The widget started as a side project to monetize our comparison data. It's becoming the primary way brands interact with our platform.


SmartReview and aversusb.net build structured product comparison tools. Learn about our embed widget at aversusb.net.

Top comments (0)