How do you know if a blog post is worth writing? For most content teams, the answer is page views or organic traffic. At SmartReview, we measure content by one thing: revenue attribution.
Here is our system for tying every piece of content to actual dollars, even when attribution is imperfect.
The Attribution Problem#
Content attribution is genuinely hard. A user might:
- Read a comparison page on Monday
- Come back directly on Wednesday
- Click an affiliate link on Friday
- Complete a purchase the following week after seeing a retargeting ad
Which touchpoint gets credit? The comparison page that started the journey? The direct visit that showed intent? The affiliate click that preceded purchase?
We use a blended model that gives partial credit to each touchpoint.
Our Attribution Model#
First-Touch vs Last-Touch vs Blended#
Most affiliate networks use last-touch attribution. This systematically undervalues top-of-funnel content (comparison pages that introduce users to products) and overvalues bottom-of-funnel content (review pages that convert already-decided users).
We track all three:
interface AttributionEvent {
sessionId: string;
pageSlug: string;
pageType: "comparison" | "review" | "blog" | "category";
timestamp: Date;
source: "organic" | "direct" | "referral" | "email";
affiliateClickId?: string;
conversionValue?: number;
}
interface ContentAttribution {
slug: string;
firstTouchRevenue: number; // 100% credit to first page in session
lastTouchRevenue: number; // 100% credit to page before affiliate click
linearRevenue: number; // Equal credit across all touchpoints
positionBasedRevenue: number; // 40% first, 40% last, 20% middle
}
We report on position-based attribution as our primary metric. It best reflects how comparison content actually works: the first page creates consideration, middle pages build conviction, the final page triggers action.
Tracking Implementation#
// Track every meaningful page interaction
function trackPageView(page: PageData) {
const sessionId = getOrCreateSessionId();
const event: AttributionEvent = {
sessionId,
pageSlug: page.slug,
pageType: page.type,
timestamp: new Date(),
source: getTrafficSource(),
};
// Store in session (for within-session attribution)
appendToSession(sessionId, event);
// Store in database (for cross-session attribution)
db.attributionEvent.create({ data: event });
}
// When affiliate click happens, close the attribution loop
function trackAffiliateClick(link: AffiliateLink) {
const sessionId = getOrCreateSessionId();
const clickId = generateClickId();
// Tag the affiliate URL with our click ID
const taggedUrl = appendParam(link.productUrl, "ref", clickId);
// Store the full session path for this click
const sessionPath = getSessionEvents(sessionId);
db.affiliateClick.create({
data: {
clickId,
sessionId,
retailer: link.retailer,
productUrl: link.productUrl,
sessionPath: JSON.stringify(sessionPath),
}
});
return taggedUrl;
}
Calculating Page-Level ROI#
Once we have attribution data, we calculate ROI per page:
async function calculatePageROI(slug: string, days: number = 30) {
const [attributionRevenue, productionCost] = await Promise.all([
getAttributionRevenue(slug, days),
getProductionCost(slug),
]);
const pageviews = await getPageviews(slug, days);
const organicTrafficValue = estimateOrganicValue(pageviews);
return {
slug,
attributionRevenue, // Actual affiliate revenue attributed
organicTrafficValue, // Estimated value of organic traffic (CPC equiv)
productionCost, // Time + AI API costs to produce
roi: (attributionRevenue - productionCost) / productionCost,
revenuePerPageview: attributionRevenue / pageviews,
paybackPeriodDays: productionCost / (attributionRevenue / days),
};
}
Estimating Organic Traffic Value#
For pages with low affiliate conversion but high organic traffic, we estimate the value using CPC equivalents:
function estimateOrganicValue(pageviews: number): number {
// Average CPC for comparison keywords is $1.20-3.50
// We use $1.80 as our baseline
const estimatedCPC = 1.80;
const estimatedCTR = 0.035; // 3.5% avg organic CTR
// Organic value = what we would have paid for this traffic via Google Ads
return pageviews estimatedCTR estimatedCPC;
}
Our Content Scorecard#
Every 30 days, we generate a scorecard ranking all pages by ROI:
| Metric | Weight | Why |
|---|---|---|
| Attribution revenue (30 days) | 40% | Direct revenue signal |
| Organic traffic value | 25% | Long-term SEO value |
| Affiliate CTR | 20% | Monetization efficiency |
| Avg time on page | 10% | Quality signal |
| Return visitor rate | 5% | Loyalty signal |
Pages scoring below a threshold get flagged for:
- Refresh (if traffic is high but conversion is low)
- Consolidation (if similar higher-performing page exists)
- Deletion (if traffic and revenue are both minimal)
What We Have Learned#
Comparison pages outperform blog posts 3:1#
Our comparison pages average $0.045 revenue per pageview. Blog posts average $0.015. The intent difference is that large.
Long-tail comparisons have better ROI than head terms#
A comparison for two niche robot vacuums (10K searches/mo, low competition) generates better ROI than AirPods vs Sony (50K searches/mo, high competition). Lower production cost, faster ranking, similar purchase intent.
Affiliate CTR is more actionable than conversion rate#
Conversion rate is controlled by the retailer. CTR is controlled by us. If CTR is low, we test: CTA placement, button copy, price display format. These changes move the needle in days, not months.
Time-to-revenue varies dramatically by category#
Mattress comparisons take 60-90 days to generate revenue (long consideration cycle). Electronics comparisons generate revenue within 7-14 days. Plan production accordingly.
The Practical Upshot#
If you are building a content business:
- Instrument everything from day one. Retrofitting attribution tracking is painful.
- Use position-based attribution, not last-touch. Last-touch penalizes your best top-of-funnel content.
- Calculate ROI per page, not per category. Your best performers will surprise you.
- Optimize CTR before conversion rate. You control the former, the retailer controls the latter.
- Separate the comparison and blog playbooks. They have different economics and different timelines.
The comparison pages that drive revenue are not always the ones with the most traffic. Revenue-per-pageview is a far better optimization target than raw traffic.
---
Part 11 of our Building SmartReview series. Previous: Part 10: Building a Partnership Pitch
Share this article
Get the best comparisons in your inbox
Weekly digest of trending comparisons, new categories, and expert insights. No spam.
Join 1,000+ readers · Unsubscribe anytime