Skip to content

Find a component

Loading the directory…

↑ ↓ to select · Enter to open · Esc to closeBrowse all →
Contributor login

Convex Checkpoints

Define user checkpoints and trigger actions when activity thresholds are met

Upstream source
git clone https://github.com/Abdssamie/convex-checkpoints.git
cd convex-checkpoints

This upstream package has not been adapted or qualified for Bijection. Read the original documentation before adopting it.

Description

Define user checkpoints and trigger actions when activity thresholds are met

Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.

Available to evaluate

Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.

Getting started

  1. Get the source at the revision above and read its package documentation.
  2. Check the required Bijection SDK version, dependencies, and external service credentials.
  3. Follow the package setup instructions and the guide to using components.
  4. Exercise the component in your deployment according to your project’s verification rules.

Open source

Maintained source: Abdssamie/convex-checkpoints. License: See repository. Consult the repository for license terms, notices, and contributor attribution.

From the upstream publisher

A Convex component for event-driven user checkpoints.

Explore the demo ↗

Upstream overview

From the upstream package documentation.

Convex Checkpoints tracks user activity milestones and triggers automated actions when thresholds are met. You define rules with factors (like 'signup' or 'create_post') and thresholds, then the component monitors progress across users and executes your callback functions when milestones are reached. It handles rule configuration, progress tracking, and completion detection while your app owns the actual side effects.

Use cases

From the upstream package documentation.

  • Onboarding sequences - Send welcome emails, tutorial prompts, or account setup reminders at specific intervals after user signup
  • Gamification systems - Award badges, unlock features, or grant achievements when users hit activity milestones like completing profiles or creating content
  • Usage-based rewards - Automatically distribute credits, discounts, or perks when users reach engagement thresholds like posting content or inviting friends
  • Progressive feature unlocks - Enable advanced functionality or remove usage limits after users demonstrate engagement through tracked activities
  • Retention campaigns - Trigger re-engagement emails or notifications based on activity patterns and milestone completion timing

How it works

From the upstream package documentation.

You configure milestone rules using checkpoints.registerRule() with a factor name, threshold value, and action identifier. The component stores these rules and tracks per-user progress in its own database tables. Your app calls checkpoints.trackEvent() from mutations after successful business logic writes, incrementing the relevant factor for that user.

When progress crosses a threshold, the component automatically schedules your onComplete callback function with details about the completed milestone. Your callback receives the user ID, factor, threshold, and optional payload data, then performs the actual side effects like sending emails or updating user credits.

The component provides both mutation-based tracking for app-driven events and HTTP endpoints for external webhook integration. For HTTP ingestion, you can POST to factor-specific routes like /checkpoints/create_post with bearer token authentication. The component includes query helpers for inspecting rules and user progress, plus test utilities for convex-test integration.

Upstream package FAQ

How does Convex Checkpoints handle rule completion callbacks?

Convex Checkpoints schedules your app-owned callback function immediately when progress crosses a threshold. The component passes details like userId, factor, and actionName to your internal mutation, where you can write to tables, schedule delayed work, or call other functions.

Can I track multiple activities for the same user?

Yes, Convex Checkpoints supports multiple factors per user. Each factor like 'signup', 'create_post', or 'profile_complete' tracks independently, and users can have progress on multiple rules simultaneously with separate thresholds and actions.

What's the difference between tracking in mutations vs HTTP endpoints?

Mutation tracking runs inside your Convex functions with full authentication and validation context. HTTP tracking is for external systems like webhooks that need to report progress server-to-server, requiring token authentication and treating requests as public endpoints.

How do I test components that use Convex Checkpoints?

Import the test component from '@abdssamie/convex-checkpoints/test' and register it with your convex-test instance. This provides the same checkpoint tracking functionality in your test environment for validating rule completion and callback execution.

Use with agents and CLI

Give your coding agent the component’s source identity and setup guidance.

agent-prompt.md
Help me integrate Convex Checkpoints with Bijection.

Read: https://bijection.com/components/abdssamie-convex-checkpoints/SKILL.md

Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.

Upstream README.md

View repository ↗

Documentation from Abdssamie/convex-checkpoints, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.

Convex Checkpoints

Convex Checkpoints lets an app define milestone rules for user activity and run a host-owned callback when a rule is completed.

It fits cases like:

  • send a welcome email 30 minutes after signup
  • grant credits after a user creates 5 posts
  • unlock a badge after profile completion

The component owns rule configuration and per-user factor progress. Your app owns auth, app data, and the callback that performs side effects.

Installation

Install the component in your app's convex/convex.config.ts:

// convex/convex.config.ts
import { defineApp } from "convex/server";
import convexCheckpoints from "@abdssamie/convex-checkpoints/convex.config.js";

const app = defineApp();
app.use(convexCheckpoints);

export default app;

Usage

Rules live in the component. Actions live in your app. The component only tracks progress and tells your callback when a rule is completed.

Configure checkpoints

Create a small app module, usually convex/checkpoints.ts.

// convex/checkpoints.ts
import { components, internal } from "./_generated/api.js";
import { internalMutation, mutation } from "./_generated/server.js";
import { v } from "convex/values";
import { ConvexCheckpoints } from "@abdssamie/convex-checkpoints";

// 1. Create one helper for the installed component.
// `onComplete` points at your app-owned callback below.
export const checkpoints = new ConvexCheckpoints(components.convexCheckpoints, {
  onComplete: internal.checkpoints.onCheckpointComplete,
});

// 2. Register rules that describe completed checkpoints.
// - factor: the activity you track, such as "signup" or "create_post"
// - threshold: the value that completes the rule
// - actionName: the app action your callback should run
export const configureRules = mutation({
  args: {},
  returns: v.null(),
  handler: async (ctx) => {
    await checkpoints.registerRule(ctx, {
      name: "welcome-after-signup",
      factor: "signup",
      threshold: 1,
      actionName: "send_welcome_email",
    });

    await checkpoints.registerRule(ctx, {
      name: "credits-after-five-posts",
      factor: "create_post",
      threshold: 5,
      actionName: "add_credits",
    });

    return null;
  },
});

// 3. Handle completed rules in your app.
// This is a normal Convex function, so it can write tables, call internal
// mutations, or schedule later work.
export const onCheckpointComplete = internalMutation({
  args: {
    userId: v.string(),
    factor: v.string(),
    ruleName: v.string(),
    actionName: v.string(),
    value: v.number(),
    threshold: v.number(),
    completedAt: v.number(),
    occurredAt: v.optional(v.number()),
    payload: v.optional(v.any()),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    switch (args.actionName) {
      case "send_welcome_email":
        await ctx.scheduler.runAfter(30 * 60 * 1000, internal.emails.sendWelcome, {
          userId: args.userId,
        });
        break;
      case "add_credits":
        await ctx.runMutation(internal.credits.add, {
          userId: args.userId,
          amount: 100,
        });
        break;
    }
    return null;
  },
});

// Optional query helpers for dashboards, debug views, and admin tools.
export const { listRules, getProgress, listProgressForUser } =
  checkpoints.api();

Track activity from app mutations

Call trackEvent after the app's real business write succeeds. In this example, creating a post increments the user's "create_post" factor. When the value reaches 5, the "credits-after-five-posts" rule completes and the callback runs with actionName: "add_credits".

// convex/posts.ts
import { mutation } from "./_generated/server.js";
import { checkpoints } from "./checkpoints.js";
import { v } from "convex/values";

export const createPost = mutation({
  args: { body: v.string() },
  handler: async (ctx, args) => {
    const userId = await requireUserId(ctx);

    // 4. First perform the real app write.
    const postId = await ctx.db.insert("posts", {
      body: args.body,
      userId,
    });

    // Then track the factor that may complete one or more rules.
    await checkpoints.trackEvent(ctx, {
      userId,
      factor: "create_post",
      payload: { postId },
    });

    return postId;
  },
});

When progress crosses a rule threshold, the wrapper schedules onComplete immediately. If an action should happen later, schedule that timing in your handler with Convex's ctx.scheduler.runAfter or ctx.scheduler.runAt, as the welcome email example does.

The component does not store callback references; the app-side wrapper schedules the typed function reference directly.

HTTP

Prefer mutation wrappers for app-driven events. They run inside your app's Convex functions, so you can authenticate the user, validate input, write app data, and track progress in one place.

HTTP ingestion is for server-to-server entry points such as webhooks or trusted backend jobs. Treat it as a public endpoint: anyone who can reach the URL can try to submit an event unless you verify the request.

The HTTP helper exposes the same trackEvent flow through routes. Use it when an external system needs to report a factor without calling your Convex mutations directly.

// convex/http.ts
import { checkpoints } from "./checkpoints.js";

export default checkpoints.http("/checkpoints", {
  token: process.env.CHECKPOINTS_SECRET,
});

This registers both POST /checkpoints and factor-specific routes such as POST /checkpoints/create_post. The factor-specific route uses the path segment as the factor, so the request body only needs the user and payload fields.

curl -X POST "$CONVEX_SITE_URL/checkpoints/create_post" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $CHECKPOINTS_SECRET" \
  -d '{"userId":"user1","postId":"post1"}'

Requests must include Authorization: Bearer <token> when token is set. Keep CHECKPOINTS_SECRET in server-side environment variables only.

Tests

When using convex-test, register the component with the test instance:

import { convexTest } from "convex-test";
import component from "@abdssamie/convex-checkpoints/test";
import schema from "./schema.js";

const modules = import.meta.glob("./**/*.*s");
const t = convexTest(schema, modules);
component.register(t);

Keywords