Find where signups drop off
Follow a new workspace from creation to its first useful dataset. Build the funnel, check its numbers, and separate a failed import from someone who still has time to finish.
Updated
The question
How many new workspaces open a dataset from their own file within seven days, and which transition stops the rest? We use the fictional file-import app from our user onboarding analytics article. Every count in this walkthrough is synthetic. Your report will show your own events.
You need a ClickClacks project and the four events below arriving from your app. The first-events walkthrough explains how to send and verify a custom event; adapt its event names to your workflow. To follow along before instrumenting your app, run the sample below in a dedicated test project. Step 6 also includes a historical dataset you can check entirely offline.
Run the sample in ClickClacks
Download onboarding-lab.mjs. It needs Node.js 20 or newer and no packages. Create a dedicated test project and a server source, then run these commands from the folder containing the download. Use the server source’s secret key in your terminal. Sending the sample adds 582 synthetic events to that project.
# Set this to the SERVER source key for your test project.
export CLICKCLACKS_SERVER_KEY="your-test-project-server-key"
node onboarding-lab.mjs prepare
node onboarding-lab.mjs validate
node onboarding-lab.mjs send- prepare saves the timestamps, IDs and expected results in
onboarding-run.json. It refuses to overwrite an existing file. - validate checks all six batches without ingesting the events.
- send submits the same saved events. Wait for
Accepted 582/582. An HTTP 202 confirms acceptance; the report becomes useful when the events are queryable. - Copy the printed People example value. In step 3 below, add a first-step filter:
demo_caseis that value. Each generated run has a different value. - Use Last 30 days, all sources, a seven-day window and Unique people. Expect 200 → 130 → 82 → 70.
The sender retries transient errors with the same saved IDs and respects Retry-After. It stops on refused events or partial acceptance. You can resend the same file before the five-minute backfill deadline to check duplication; do not run prepare again for a transport retry. In our local test project, sending the full batch twice left exactly 582 stored events.
The screenshots below come from this synthetic run in a local ClickClacks project, using the ingestion validator and real analytics queries. Its fixed run name was onboarding-guide; use the random case value printed by your own download.
1. Define activation
For this app, creating an account is the start. Opening a dataset made from the user’s own file is our candidate activation event: it shows the core workflow has worked. Whether that predicts continued use is a separate question to check with retention data.
Workspace created: the workspace has been saved.File submitted: the app has accepted a file for processing.Import succeeded: processing has completed successfully.Dataset opened: the resulting dataset has been displayed.
The seven-day clock starts at Workspace created. Keep optional invitations and profile setup out of these required steps. Analyze people who join an existing workspace separately: they do not take this route.
2. Check the events
- Complete the route with a test account and open Realtime to find its events.
- Check the four names, their order and the person identity. Confirm the success event corresponds to a completed import, rather than an upload-button click.
- Open Lexicon under Data and search for each event. Check that the spellings used by the funnel match the events you receive.
Background jobs and retries
Emit File submitted after the application accepts a file, and Import succeeded after the import job successfully commits its output. A queued job can fail after the browser closes, so the worker should report its outcome. Persist the submitting user and workspace on the job; do not replace that user with a generic “background-worker” identity.
// Application pseudocode: adapt the transaction to your database.
await database.transaction(async (tx) => {
const transitioned = await tx.importJobs.markSucceededIfRunning(job.id)
if (!transitioned) return // A repeated worker delivery changed nothing.
await tx.analyticsOutbox.insert({
event: "Import succeeded",
distinct_id: job.submittedByUserId,
timestamp: new Date().toISOString(),
insert_id: "import-" + job.id + "-success",
properties: {
job_id: job.id,
attempt: job.attempt,
file_type: "csv",
$groups: { workspace: job.workspaceId }
}
})
})An outbox is a database table of events waiting to be sent. Saving the job’s successful transition and its outbox event in one transaction prevents a crash between those writes from silently losing the event. A separate sender delivers the stored payload and marks it sent only after acceptance. Give the outbox a unique constraint on its transition ID.
- Transport retry: reuse the persisted
insert_id, original timestamp and properties. Do not assign a new ID when a timeout makes the response uncertain. - Real application retry: a corrected file is a new submission with its own attempt and event ID. The sample includes 12 corrected submissions: 142 submission events still represent 130 submitting people.
- Identity: use the same stable user ID for a person’s browser and server events. For different teammates, keep their real identities and connect events through the workspace group.
- Delivery failures: monitor outbox age and failed attempts. Surface validation errors, warnings and partial acceptance; do not treat every 2xx response as a fully accepted batch. Alert before an unsent event exceeds the seven-day timestamp limit.
The example transition ID assumes job IDs contain only letters, numbers, underscores or hyphens and the complete ID is at most 80 characters. Hash longer or differently formatted IDs, as the downloadable sender does. See the server API reference for payload and error rules.
3. Build the funnel
- Open Funnels and click New funnel.
- Pick
Workspace createdas the first event. - Use + Add step to add
File submitted,Import succeededandDataset opened, in that order. - Use + Filter on a step only when your definition requires a property value. Keep the first version simple enough to verify with a known test account.
For the download, the required filter belongs on Workspace created: demo_case is your printed people-example value. This keeps the separate team example and any earlier runs out of the funnel.
4. Set window, count and order
- Conversion window: 7 days from workspace creation.
- Count: Unique people. If Count by is visible, choose People for this example.
- Steps must happen in order: leave it on. Other events, including a validation error or help-page visit, can happen between the required steps.
5. Save it

Name it Activation: workspace → dataset. Click Save funnel, then choose a board or Save without a board. The saved report uses the filter bar’s dates. Choose a period after all four events were instrumented and long enough for at least some entrants to have had the full week.
6. Verify the result
Start with a cohort that has had the full window. Once the generated run’s printed deadline has passed, 160 workspaces have had seven days to finish. Their four step counts are 160 → 120 → 72 → 60.
- Conversion: 60 / 160 = 37.5%.
- Biggest drop: submission → success loses 48 of 120 workspaces, or 40%.
- Other drops: 40 never submit; 12 import successfully but do not open the dataset within the window.
Now include 40 more workspaces created one day before preparation. Ten have already finished; 30 have not submitted yet. The report has 200 entrants and 70 completions, so overall conversion is 35%. Of the 130 unfinished entrants, 100 have expired windows and 30 are pending.

With all 200 entrants included, submission → success is 48 / 130 = 36.9%. In the finished cohort alone, it is 48 / 120 = 40%. The number of expired drop-offs is the same; the denominator changed.
To check the arithmetic offline, download the sample events and the verification script into one folder. With Node.js installed, run the command below. The files are a local teaching dataset, not an import format for the ClickClacks ingestion API. They contain no customer data and do not send anything to a server. This fixed dataset uses September 20 and September 29 entries with an October 1, 2026 cutoff; its counts match the fresh run, but its timestamps are historical.
node verify-onboarding.mjs onboarding-events.jsonFinished windows: 160 → 120 → 72 → 60
Finished-window conversion: 37.5%
All entrants: 200 → 130 → 82 → 70
Overall conversion: 35%
Unfinished: 100 expired, 30 pending
Submitted: 60 direct successes, 30 error encounters, 30 unresolved
Error encounters: 12 recovered, 18 unrecoveredFor your own events, verify one known completed person and one unfinished person before trusting the totals. Record the report dates, window, counting unit and step filters so another teammate can reproduce the report.
7. Investigate the drop
- At submission → success, click the drop percentage or the dropped count in the table to open the drop-off drawer.
- Open People. The drawer starts with expired windows; if it offers a cohort switch, keep Window expired selected. In the sample, this drop contains 48 people and no pending entrants.
- Inspect What they did instead and Where they were, then open individual event timelines.
- Compare missing success events with the application’s import-job records before deciding there is a usability problem.
The sample has 30 workspaces with validation errors. Twelve recover and complete an import, leaving 18 unrecovered. Another 30 submitted workspaces have neither a success nor a recorded validation error. Together, those 18 + 30 explain the 48-person drop. Counting all 30 error encounters as failed onboarding would include the 12 recoveries.

In this sample the drawer labels the 30 missing later events Nothing — session ended. Treat that as “no later recorded event,” then check the import jobs. It does not prove that the person deliberately abandoned the app.
Show paths between these steps opens Flows for a broader exploration. Its session rules and filters can differ from the funnel’s expired-window audience. Keep the drawer as the reference for these 48 people; see the handoff details before comparing counts.
8. Choose a useful breakdown
Try a property with a plausible connection to the issue, such as device, or compare saved segments. A funnel property breakdown uses the value on the first-step event. An error category recorded only on a later validation event will not automatically split workspace creation by that error.
Read the table for small groups: the chart draws only the top three breakdown values with at least 500 entrants each. The 200-person example is below that threshold. Avoid treating a handful of accounts in one slice as proof of a general pattern.
9. Compare complete windows
Switch Conversion by step to Over time to group results by entry day. Recent days can look worse because entrants have had less time. Check the pending counts and compare cohorts with a full seven days of observation before saying activation improved or declined.
Suppose you add a downloadable file template and a clearer missing-header message. Track recovery from that error and keep dataset opening as the outcome. Record the release date and keep the event definitions stable. A before-and-after difference alone does not establish that the change caused the result.
10. Keep the definition on a board
- On the saved funnel, click Add to board.
- Choose Linked so the tile follows edits to the saved funnel.
- Choose the board and its filter behavior. Check the dates again after adding the tile.
- Keep a note with the activation definition, counting unit, seven-day window, instrumentation start date and the next investigation.
A useful review starts with “48 of 120 submitting workspaces did not complete an import within seven days.” It then separates the 18 unrecovered errors from the 30 unresolved cases, and names the next check for each group.
When teammates share the work
The download also sends a separate 20-workspace example. An owner creates each workspace, an operator submits and imports a file, and an analyst opens the dataset. Every person keeps their own distinct_id. Every event carries the same workspace ID for that team in properties.$groups.workspace.
{
"event": "Dataset opened",
"distinct_id": "analyst-17",
"insert_id": "dataset-42-opened-visit-1",
"properties": {
"$groups": { "workspace": "workspace-42" }
}
} Sending a group profile can give a workspace a name and traits, but the events themselves need their group association. An ordinary workspace_id property does not replace $groups.workspace. Check the Companies guide if the workspace type is missing from your project’s Count by control.
- Create another four-step funnel and set the first-step
demo_casefilter to the printed Team example value. - Keep the seven-day window and ordered steps. With people as the counting unit, the result is 20 → 0 → 0 → 0: none of the owners submitted a file themselves.
- In the builder, choose the workspace type under Count by and save. The same events now produce 20 → 16 → 12 → 10, or 50% workspace activation.

Choose the unit before interpreting the result. “How many people complete this workflow?” and “How many workspaces reach value?” are different questions. Merging teammates into one person would make person-level analysis misleading.
Troubleshooting
- The download rejects old timestamps. Complete preparation, validation and sending within five minutes. A fresh run needs a new file and a matching new case filter; a partially delivered old run must not be retimestamped.
- The sample’s pending count is too high. Wait until the printed window-end time, allow another minute for the report cutoff, then refresh. Keep Last 30 days selected.
- The preview and saved funnel disagree. Match their dates first. The preview uses 30 or 90 days; the saved report uses the filter bar.
- You can see a success event, but the person did not convert. Check that it belongs to the same identity, follows the required earlier steps and falls within the window and report dates. Also check step filters.
- A reload changes the totals unexpectedly. Confirm Count is Unique people. Events mode counts person-and-session pairs, so it answers a different question.
- Your workspace totals exceed the account list. Check whether you counted people when several teammates share one workspace. Configure group identity and Count by for the account question.
- The most recent cohort looks worse. Read pending versus expired before changing onboarding. A historical report can end before entrants’ windows finish.
- Successes are missing before a certain date. Start the analysis after instrumentation went live. Earlier entrants cannot produce events that were not being collected.
- A filter disappears when you reopen the funnel. Save required step filters in the builder with + Filter. Filters applied only to the current report page are not part of the saved definition.
Next
Once you trust the activation count, check whether those people return: Are users coming back?