Guides

Year-in-review stories made by your app, one user at a time

By Lucency, the makers of Yearcap · Updated November 3, 2026

Some apps keep everything on the phone, so there is no spreadsheet of every user to upload. Yearcap can still give each of them a story: your app sends one user’s stats when they tap “See my year”, and opens the private story link it gets back. Here is the whole setup.

How it works

  1. A user taps See my 2026 in your app.
  2. Your app sends that user’s stats to Yearcap with your app key.
  3. Yearcap answers with the user’s private story link. Your app opens it in the browser or a web view.

Only that one user’s numbers leave the phone, and only when they ask. Sending the same user again updates their numbers and keeps the same link, so a tap in late December shows the whole year.

Set it up once

  1. Make a campaign with a small export: your own stats are enough. Its columns are the columns your app will send, and it’s where you pick the cards, the theme and your colors.
  2. Publish it. You land on your dashboard. Signing in first (GitHub or Google) is optional, but it keeps the dashboard in your account and tells us where to send plan emails. To try it for free, pick the Pop or Paper theme: the others need a paid plan.
  3. Under Let your app make each story, press Make an app key. The dashboard shows the key and the request with your own column names.

The app key can only add stories, so it’s fine to ship it inside your app. Someone who digs it out of the app could add made-up users up to your plan’s limit, though. If you see strange users on your dashboard, make a new key and the old one stops working.

Test in a separate campaign. Every user you add counts toward your plan and stays until the campaign ends, so try things in a test campaign, then delete it and set up a fresh one for your real users.

The request

POST https://yearcap.co/api/story
Authorization: Bearer yc_your_app_key
Content-Type: application/json

{
  "user_id": "a1b2c3",
  "first_name": "Ana",
  "workouts": 146,
  "kg_lifted": 12400
}

CSV works too, with Content-Type: text/csv: a header line and the user’s line.

user_id,first_name,workouts,kg_lifted
a1b2c3,Ana,146,12400

The answer

{
  "url": "https://yearcap.co/r/your-app-x1y2/SEKgsWajQNSZ2ZVr",
  "shareUrl": "https://yearcap.co/s/your-app-x1y2/aOmweiohxQbQ",
  "added": true
}

url is the user’s own story: open it for them. shareUrl is the public summary card their friends see when they share it. added is false when the user already had a story.

In Swift

func openYearStory(stats: [String: Any]) async throws {
    var req = URLRequest(url: URL(string: "https://yearcap.co/api/story")!)
    req.httpMethod = "POST"
    req.setValue("Bearer \(yearcapAppKey)", forHTTPHeaderField: "Authorization")
    req.setValue("application/json", forHTTPHeaderField: "Content-Type")
    req.httpBody = try JSONSerialization.data(withJSONObject: stats)

    let (data, response) = try await URLSession.shared.data(for: req)
    guard (response as? HTTPURLResponse)?.statusCode == 200,
          let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
          let link = json["url"] as? String, let url = URL(string: link) else {
        // Show "Your year isn't ready yet" and try again later.
        return
    }
    await UIApplication.shared.open(url) // or an SFSafariViewController
}

When something goes wrong

StatusWhat it meansWhat to show the user
200The story is ready. Open url.The story.
400The id column is missing, or the body isn’t one JSON object or a two-line CSV.A bug on your side: log it.
401The app key is wrong, or was replaced on the dashboard.“Your year isn’t ready yet.”
402The plan is full, or the campaign uses a paid theme on the Free plan. Users who already have a story still get theirs.“Your year isn’t ready yet.” You get an email at 90% and when it’s full.
410The campaign has ended: stories stay up for 90 days after you publish.Nothing: hide the button.
413The body is over 20 KB. Send one user at a time.A bug on your side: log it.

Every error comes with a short error message in the JSON, written for you, not for your users.

Plans and limits

Stuck?

Email support@yearcap.co and we’ll help you get it working.

Make your users’ year in about ten minutes

Drop in one spreadsheet and watch the story build live. Free up to 500 users.

Make yours, free