ScreenshotNeo

BlogHow-to

How to Create Personalized Infographics for Year-in-Review Campaigns

A practical guide to turning each user’s annual data into a localized, shareable infographic with reliable automation and delivery.

By the ScreenshotNeo team1 October 20269 min read

Personalized year-in-review infographics work when every image tells one clear story: what the person did, what stands out, and what they can do next. Build them as data-driven templates rather than manually editing one design at a time.

The reliable workflow is:

  1. Define the audience, purpose, and narrative.
  2. Choose a compact set of meaningful metrics.
  3. Normalize each user’s data into a documented schema.
  4. Map fields to a reusable visual template.
  5. Generate one variant per user with locale and fallback handling.
  6. Proof, capture, export, and distribute.

Adobe describes an infographic as a way to tell a data story at a glance, while Canva recommends starting with the audience and purpose before choosing visual forms. Adobe’s business infographic guidance and Canva’s data-presentation guidance provide the source principles.

1. Define the story before designing

Write the recap as a four-part narrative:

  1. Setup: identify the period and the person.
  2. Insight: show the dominant activity, category, or milestone.
  3. Implication: explain what the pattern means in plain language.
  4. Action: finish with one useful next step or call to action.

For example: “In 2025, Maya created 48 projects. Brand work was her largest category, placing her in the top 12%. Try the new brand kit for your next project.” The exact copy depends on your product, but the hierarchy should remain stable across variants.

Choose the audience and channel

Channel Design decision Validation
Email Use a compact width and make the main insight readable without zooming. Test on narrow screens and with images blocked.
Social sharing Use a square or portrait composition with a short headline. Check cropping in each target network.
Account dashboard Use a larger, information-rich layout and a clear CTA. Check keyboard focus around the download or share action.
Downloadable report Use a print-safe layout and a PDF export. Check page breaks, margins, and font embedding.

2. Select a compact metric set

Include only fields that advance the story. A practical annual recap can contain:

  • Total activity for the period.
  • Top category or content type.
  • Change over time, such as monthly activity.
  • Relative ranking or percentile.
  • Milestones reached.
  • A theme, personality, or emerging trend.
  • A generated message or short poem.
  • An image or avatar.
  • A closing CTA URL.

Adobe recommends focusing on results and variables that explain the situation rather than adding every available measure. Use Adobe’s data-story guidance to review whether each metric earns space.

Use a versioned data contract

Define the fields before designing the template. This makes generation deterministic and gives engineering, design, localization, and QA a shared contract.

{
  "user_id": "u_4821",
  "locale": "en-US",
  "period": "2025",
  "total_activity": 48,
  "top_category": "Brand projects",
  "rank_or_percentile": 88,
  "monthly_activity": [2, 3, 4, 6, 5, 3, 4, 5, 4, 6, 3, 3],
  "milestones": ["First team project", "25th project"],
  "theme_or_personality": "The Builder",
  "generated_message": "You turned ideas into a system.",
  "image_or_avatar": null,
  "cta_url": "https://example.com/next-step"
}

Document null handling, number formatting, pluralization, date formatting, and allowed ranges. For example, if rank_or_percentile is missing, render “You completed 48 projects” instead of an empty badge. If a user has no activity, use an honest zero-state message and a CTA that helps them begin.

3. Map metrics to visual forms

Question Recommended form Implementation note
How did activity change each month? Line chart Keep the axis scale consistent across variants.
Which categories were largest? Horizontal bars Sort descending and limit the number of bars.
How do two periods compare? Columns Label the values directly where possible.
What share came from each category? Donut or pie Use only a few parts and show totals beside the chart.
What did the person accomplish? Milestone cards Use short labels and a consistent icon treatment.

These mappings follow the chart guidance in Adobe’s infographic article and Canva’s infographic guide. Canva also notes that there is no one-size-fits-all infographic layout, so let the information determine the arrangement.

4. Build a reusable HTML/SVG template

HTML and inline SVG are useful when your values, labels, and chart geometry change for every user. The following Python program writes a complete, self-contained SVG infographic. It has no external packages.

from pathlib import Path
from html import escape
import json

record = {
    "name": "Maya",
    "period": "2025",
    "total_activity": 48,
    "top_category": "Brand projects",
    "percentile": 88,
    "monthly_activity": [2, 3, 4, 6, 5, 3, 4, 5, 4, 6, 3, 3],
    "message": "You turned ideas into a system."
}

W, H = 1200, 1500
values = record["monthly_activity"]
max_value = max(values) or 1
points = []
for i, value in enumerate(values):
    x = 90 + i * (1020 / (len(values) - 1))
    y = 1010 - (value / max_value) * 220
    points.append(f"{x:.1f},{y:.1f}")

svg = f'''
  
  
  {escape(record["period"])} YEAR IN REVIEW
  {escape(record["name"])}’s year
  {escape(record["message"])}
  
  TOTAL ACTIVITY
  {record["total_activity"]}
  TOP CATEGORY
  {escape(record["top_category"])}
  PERCENTILE
  Top {100-record["percentile"]}%
  Monthly activity
  
  
  Keep building in {int(record["period"])+1}.
  
  See what’s next
'''

Path("year-review.svg").write_text(svg, encoding="utf-8")
print("Wrote year-review.svg")

Replace the hard-coded record with a database query or JSON input, then validate every field before rendering. Keep the template geometry stable so visual QA can compare variants reliably.

5. Generate variants at scale

Template-first tools

Choose based on template speed versus pixel-level control, manual editing versus automated replacement, collaboration and approvals, output formats, localization and fallback handling, and expected audience volume.

Automated field replacement

Canva’s DesignDNA campaign is a useful example of structured personalization: Canva reported 95 million unique DesignDNAs and combined locale, total designs, top design type, relative ranking, design personality, a generated poem, and an emerging trend. Read the Canva Engineering case study for the implementation context.

6. Capture the finished image

If you render HTML, a browser capture step turns each variant into a PNG, JPEG, WebP, or PDF. A local Playwright example is:

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1200, height: 1500 }, deviceScaleFactor: 2 });
await page.goto('file:///absolute/path/to/year-review.html', { waitUntil: 'networkidle' });
await page.screenshot({ path: 'year-review.png', fullPage: true });
await browser.close();

For production, wait for fonts and images explicitly, freeze animation, set the intended timezone and locale, and use a deterministic viewport. Keep the source data alongside the output so a failed or disputed image can be regenerated.

7. Proof and distribute

  • Verify the person’s name, period, totals, ranking, and CTA URL.
  • Check thousands separators, decimal rules, pluralization, and date formats for every locale.
  • Check long names, long category labels, right-to-left text, and missing avatars.
  • Inspect chart scales so a small difference is not made to look dramatic.
  • Check clipping, line wrapping, contrast, and reading order.
  • Export PNG or JPEG for social and email; export PDF when a print-oriented file is needed. Canva documents these export and resizing paths in its infographic guide.
  • Store a content hash, template version, input record version, and output URL for reproducibility.

8. Or skip the browser setup

ScreenshotNeo captures a rendered URL with one request, returning PNG, JPEG, WebP, or PDF. It is the first screenshot API to try when you need clean share images: cookie and consent banners, newsletter popups, and chat widgets are removed before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

Put your personalized HTML at a URL, then call the API. Full option details are in the ScreenshotNeo 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}`);

ScreenshotNeo supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets and arbitrary viewports, retina scale, PDF paper size and margins, custom CSS and JavaScript, click and wait actions, request and resource blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API, and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which helps when switching.

Only clean shots are billed. Responses identify the result with X-Page-Verdict and X-Billed headers. Plans include 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots, with every feature available on every plan. Create a free ScreenshotNeo account.

9. Performance, reliability, and cost

Performance

  • Generate data and validate records before opening a browser.
  • Reuse a template and fonts instead of rebuilding them per request.
  • Use a fixed viewport and avoid unnecessary third-party resources.
  • Use caching with a chosen TTL when the same URL and inputs can be reused.
  • Use bulk capture for up to 100 URLs per call when producing a batch.
  • Use asynchronous jobs and signed webhooks for large campaigns rather than holding one request open.

Reliability

  • Retry transient network failures with bounded exponential backoff.
  • Persist input records and template versions so outputs are reproducible.
  • Check verdict and billing headers before treating a response as a successful image.
  • Quarantine records with invalid values instead of silently rendering misleading graphics.
  • Run a visual sample of every locale, template branch, and edge case before release.

Cost

Your main cost drivers are the number of variants, recapture frequency, browser rendering time, and whether you generate multiple formats. Cache immutable annual recaps, avoid recapturing unchanged records, and choose output dimensions deliberately. ScreenshotNeo does not bill bot checks, blank pages, timeouts, failed loads, or cache hits; review the documentation for request options and usage reporting.

10. Troubleshooting

Symptom Likely cause Fix
Name or number is clipped Text length exceeds the template’s fixed box. Add wrapping or truncation rules, test long names, and reserve space for localization.
Chart looks misleading Different variants use inconsistent axes or slices. Use a stable scale and label values directly.
Missing data creates blank areas Null handling was not defined. Render an explicit fallback sentence or hide the component intentionally.
Wrong language or date Locale was applied only to copy, not formatting. Pass locale and timezone through number, date, and pluralization formatters.
Screenshot is blank The page was captured before rendering completed or a bot check blocked it. Wait for a selector or network idle, inspect the page verdict, and verify the source URL.
Popups cover the infographic Consent, newsletter, or chat scripts loaded after the page. Use ScreenshotNeo’s cleanup steps or disable those scripts in your own render.
Fonts differ between runs Fonts loaded late or were unavailable. Self-host approved fonts, wait for document.fonts.ready, and keep a deterministic fallback.
PDF has unexpected page breaks Content height exceeds the selected paper size. Set paper size, margins, orientation, and page ranges explicitly, then inspect a sample PDF.
API response is not an image Authentication, URL encoding, or a target-page failure. Check status, response headers, X-Page-Verdict, and X-Billed; encode the URL and confirm the access key.

11. FAQ

How many metrics should one recap contain?

Use the smallest set that supports the story. Start with a total, one dominant comparison, one trend or milestone, and a CTA; add fields only when they clarify the user’s result.

Should every user receive the same layout?

Keep the hierarchy and component positions stable, but allow controlled variants for missing data, long localized text, and different activity ranges.

Can I create both social images and PDFs?

Yes. Maintain one data contract and provide separate templates or capture settings for image dimensions and PDF paper, margins, orientation, and page ranges.

How do I handle users with no activity?

Use a zero-state variant with accurate language, no invented rankings, and a relevant next-step CTA.

When should I use a no-code workflow?

Use a template replacement workflow such as Placid with Make when the fields and approvals are straightforward. Use code when you need custom chart logic, complex localization, or high-volume reproducibility.