Complete Guide: Login Streak Milestones → Gamified Rewards + Engagement with n8n

Your users signed up, logged in twice, and vanished. This is the single most expensive leak in any SaaS or community product: not acquisition cost, but the silent churn of people who never built a hab

Complete Guide: Login Streak Milestones → Gamified Rewards + Engagement with n8n

Your users signed up, logged in twice, and vanished. This is the single most expensive leak in any SaaS or community product: not acquisition cost, but the silent churn of people who never built a habit. Streaks fix this — the same mechanic that made Duolingo, Snapchat, and GitHub's contribution graph impossible to put down. But most teams never ship streaks because the reward logic is annoying to build: you have to track consecutive-day activity per user, detect the exact moment someone crosses a milestone, and fire the right reward without double-sending or missing anyone. This guide shows you how to automate all of it with n8n — detecting 7, 30, 90, and 365-day login streaks and delivering a badge, discount code, or upgrade via email and Slack, with zero manual work.

The Problem: Engagement Loops Are Hard to Operationalize

Everyone agrees gamification works. The reason it rarely ships is operational, not conceptual. To reward a streak you need to answer three questions on a schedule, for every user, forever:

  • Did this user log in today? You need a reliable event source — your auth logs, a last_login column, or a product analytics tool.
  • Is today part of an unbroken chain? A streak is not "days active." It's consecutive days. Miss one day and the counter resets to 1. That comparison logic is where hand-rolled scripts get buggy.
  • Did they just cross a milestone today? You want to congratulate someone on day 7 exactly once — not every day after, and not never. Idempotency is the hard part.

Done manually, this becomes a spreadsheet nobody updates. Done as custom code, it becomes a cron job nobody maintains. n8n sits in the sweet spot: a visual, scheduled workflow that reads your data, runs the streak math, and dispatches rewards — auditable and editable without redeploying anything.

The Solution: A Scheduled Streak Engine in n8n

The workflow runs once a day, early, before your users are active. At a high level it does five things:

  1. Schedule Trigger fires at a fixed hour (say 05:00).
  2. A database or HTTP node pulls the login history for every active user.
  3. A Code node computes each user's current consecutive-day streak.
  4. A Switch node checks whether that streak equals a milestone (7, 30, 90, 365) that hasn't been rewarded yet.
  5. Email and Slack nodes deliver the matching reward, and a write-back node records that it was sent.

The critical design decision is milestone equality, not threshold. You check streak === 7, not streak >= 7. Because the workflow runs daily and a streak only increments by one per day, an exact-match check guarantees each milestone fires exactly once per user, per achievement — no idempotency table strictly required, though we'll add one as a safety net.

Step-by-Step Setup in n8n

1. Schedule Trigger. Add a Schedule Trigger node. Set it to a Cron expression like 0 5 * * * so it runs daily at 05:00 in your account timezone. Running before peak usage means the previous day's logins are fully settled.

2. Fetch login data. Add a Postgres (or MySQL / HTTP Request) node. If your logins live in a table, query the distinct login dates per user for the last ~370 days:

SELECT user_id, email, slack_id, DATE(logged_in_at) AS day FROM sessions WHERE logged_in_at > NOW() - INTERVAL '370 days' GROUP BY user_id, email, slack_id, DATE(logged_in_at) ORDER BY user_id, day;

If your source is an API (Amplitude, Mixpanel, your own backend), use the HTTP Request node with pagination enabled instead.

3. Compute the streak. Add a Code node set to "Run Once for All Items." Group the rows by user, sort each user's days descending, then walk backward from today counting unbroken consecutive days:

const byUser = {};
for (const item of $input.all()) {
  const u = item.json;
  (byUser[u.user_id] ??= { email: u.email, slack_id: u.slack_id, days: [] }).days.push(u.day);
}
const MS = 86400000;
const results = [];
for (const [id, u] of Object.entries(byUser)) {
  const set = new Set(u.days);
  let streak = 0;
  let cursor = new Date(); cursor.setHours(0,0,0,0);
  while (set.has(cursor.toISOString().slice(0,10))) { streak++; cursor = new Date(cursor - MS); }
  results.push({ json: { user_id: id, email: u.email, slack_id: u.slack_id, streak } });
}
return results;

This returns one item per user carrying their exact current streak. Note it tolerates a missing login today — if the user hasn't logged in yet this morning but did yesterday, you may prefer to start the cursor at yesterday. Adjust the initial cursor to taste.

4. Match milestones. Add a Filter node (or IF node) that only passes items where streak is one of [7, 30, 90, 365]. Use the expression {{ [7,30,90,365].includes($json.streak) }}. Everyone else drops out silently — no reward, no noise.

5. Route to the right reward. Add a Switch node keyed on {{ $json.streak }} with four outputs. Map each to its reward: day 7 → a "Getting Started" badge; day 30 → a 15% discount code; day 90 → a premium feature unlock; day 365 → a free plan upgrade or lifetime perk. For discount codes, insert an HTTP Request node before the email that calls your billing provider (Stripe, Gumroad, Paddle) to generate a unique coupon so codes can't be shared.

6. Deliver via email and Slack. On each Switch branch, add a Send Email (SMTP or your ESP like SendGrid/Postmark) node and a Slack node in parallel. The email celebrates the achievement and includes the reward; the Slack message posts to the user's DM via slack_id, or to your internal #wins channel so your team sees engagement momentum in real time. Personalize with {{ $json.email }} and {{ $json.streak }}.

7. Write back (idempotency safety net). Finish with a database Update node that records rewarded_milestone = {{ $json.streak }} and a timestamp. Add a check earlier in the flow so that even if the workflow runs twice in one day, an already-rewarded milestone won't fire again. This protects you against manual re-runs and timezone edge cases.

Benefits: What This Actually Buys You

  • Habit formation on autopilot. The streak counter gives users a reason to return daily, and the milestone rewards give them a payoff that compounds loyalty. You built the loop once; it runs every day without you.
  • Zero manual reward ops. No support agent hand-issuing discount codes, no PM remembering to congratulate power users. The right reward reaches the right person the morning they earn it.
  • Real-time engagement visibility. Piping milestones into a Slack channel turns retention into something your whole team feels, not a number in a dashboard nobody opens.
  • Fully editable logic. Want to add a 180-day tier or swap the day-30 reward? Edit one Switch branch. No deploy, no engineering ticket.
  • Provider-agnostic. Swap Postgres for MySQL, SendGrid for Postmark, Stripe for Gumroad — the streak engine stays the same.

Common Pitfalls (and How to Dodge Them)

Timezones will bite you. If your database stores UTC but your users are in Tokyo, "today" is ambiguous and a user can appear to skip a day they didn't. Normalize all login timestamps to a single timezone in your SQL query (or in the Code node) before comparing dates. Pick one timezone and stick to it.

Threshold logic double-sends. Using streak >= 7 instead of streak === 7 means every day past 7 re-triggers the day-7 reward. Always match milestones by equality, and keep the write-back guard as backup.

Duplicate logins inflate streaks. If a user logs in three times on Monday, that's still one day. Deduplicate to distinct calendar days (the GROUP BY DATE(...) in the query handles this) before counting.

The workflow silently fails. A daily job that breaks is invisible until users complain they never got rewarded. Add an Error Trigger workflow that pings your Slack #alerts channel whenever the streak engine throws, so a broken query or expired credential surfaces the same day.

Reward fatigue and gaming. If rewards are too frequent or too easy to farm, they lose meaning. Space milestones out (7/30/90/365 is a deliberate exponential curve) and use single-use, user-bound discount codes so a day-30 coupon can't be posted publicly and drained.

Ship this once and you have a self-running engagement engine that turns casual signups into daily-active loyalists — the cheapest retention lever in your stack, running quietly at 5 a.m. every day.

Login Streak Milestones → Gamified Rewards + Engagement
PRONTO PARA USAR

Ja construimos isso pra voce

Nao comece do zero. O Login Streak Milestones → Gamified Rewards + Engagement e um workflow n8n pronto para instalar — conecta suas ferramentas em minutos, sem codigo.

Instalar por $79 →