|
| 1 | +--- |
| 2 | +title: Workflows best practices |
| 3 | +sidebar: Docs |
| 4 | +showTitle: true |
| 5 | +--- |
| 6 | + |
| 7 | +## Boundaries |
| 8 | +### Define clear triggers and avoid overlapping workflows |
| 9 | + |
| 10 | +Use a single well-defined trigger per workflow (e.g. “user sign-up”, “purchase completed”, or a webhook), so the logic is clear. PostHog defines that every workflow starts with a trigger and end with an exit. |
| 11 | + |
| 12 | +Avoid multiple workflows that respond to the same event and perform overlapping actions as this can cause duplicate messages or conflicting side-effects. |
| 13 | + |
| 14 | +If you really need multiple workflows on the same event, consider whether a single workflow with [audience splits](/docs/workflows/workflow-builder#audience-splits)/branching logic would serve better. |
| 15 | + |
| 16 | +### Minimize deduplication and side-effects |
| 17 | + |
| 18 | +Don’t duplicate workflows that do essentially the same thing under slightly different triggers, which increases the risk of duplicate messages, conflicting updates, or unexpected user experience. |
| 19 | + |
| 20 | +Avoid side-effects where possible. For example, don’t rely too heavily on property updates or event triggers inside a workflow, treat automations as eventual side-effects, not core business logic. |
| 21 | + |
| 22 | +## Logic, branching, and timing |
| 23 | +### Limit complexity and keep logic as simple as possible |
| 24 | + |
| 25 | +Use minimal branching and splits. Complex branching can make workflows hard to reason about. |
| 26 | + |
| 27 | +<ProductScreenshot |
| 28 | + imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/Clean_Shot_2025_12_05_at_14_33_41_2x_278ad5fae8.png" |
| 29 | + imageDark="https://res.cloudinary.com/dmukukwp6/image/upload/Clean_Shot_2025_12_05_at_14_33_41_2x_278ad5fae8.png" |
| 30 | + alt="Workflow complexity example" |
| 31 | + classes="rounded" |
| 32 | +/> |
| 33 | + |
| 34 | +If you find yourself duplicating logic across multiple workflows, consider refactoring: either unify into one workflow or extract repeated logic into reusable sub-workflows (if supported), or design event properties in a way that triggers workflows cleanly. |
| 35 | + |
| 36 | +### Use delays and conditions responsibly |
| 37 | + |
| 38 | +Use delay steps (e.g. “wait 2 days”) or conditional logic only when necessary. Overuse can lead to unpredictable states, e.g. if user attributes change during the delay, or if event data evolves. |
| 39 | + |
| 40 | +Keep records/logs where possible, especially for later debugging (e.g. knowing that a user was “waiting in step N of workflow X”). |
| 41 | + |
| 42 | +### Design for fallback and safe defaults |
| 43 | + |
| 44 | +For actions that send messages or update user data: ensure that if some data is missing (e.g. user email, user property) the workflow safely skips or uses defaults rather than failing or sending bad messages. |
| 45 | + |
| 46 | +<ProductScreenshot |
| 47 | + imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/error_handling_28a45d2ecf.png" |
| 48 | + imageDark="https://res.cloudinary.com/dmukukwp6/image/upload/error_handling_28a45d2ecf.png" |
| 49 | + alt="Error handling in workflows" |
| 50 | + classes="rounded" |
| 51 | +/> |
| 52 | + |
| 53 | +## Testing setups and delivery |
| 54 | + |
| 55 | +### Ensure messaging channels are properly configured and tested |
| 56 | + |
| 57 | +Before sending emails or other messages, [set up and verify your channels](/docs/workflows/configure-channels). For email: configure "from" name, from-address, and DNS (SPF/DKIM) to avoid spam/folder issues. |
| 58 | + |
| 59 | +Use templating and personalization carefully (e.g. with placeholders like `{{ person.name }}`), but also verify that placeholders resolve and avoid sending messages with unresolved variables. |
| 60 | + |
| 61 | +If sending to external channels (e.g. Slack, SMS, webhooks), treat them as equally important as email: ensure you have fallback or error handling logic (e.g. when a webhook endpoint fails). |
| 62 | + |
| 63 | +### Test workflows in a safe environment or subset first (staging/small user group) |
| 64 | + |
| 65 | +Before a full rollout: test with internal users or a small percentage of real users. Monitor delivery for emails and messages, event logs, user property updates, or other side-effects. Watch for unintended behavior: |
| 66 | +- multiple emails |
| 67 | +- loops (i.e. your workflow triggers events that retrigger the same workflow) |
| 68 | +- delays stacking up |
| 69 | + |
| 70 | +## Observability and limits |
| 71 | + |
| 72 | +### Monitor and log |
| 73 | + |
| 74 | +Ensure that failures (e.g. email bounce, webhook error) are captured and surfaced. When facing a problem, check the “[Troubleshooting & FAQs](/docs/workflows/troubleshooting)” section for Workflows. |
| 75 | + |
| 76 | +For long-running workflows (with delays), track user state (which step they are in), and provide a way to debug or abort if something goes wrong. |
| 77 | +Periodically review metrics: how many messages sent, how many workflows triggered, bounce/failure rate, etc. |
| 78 | + |
| 79 | +<ProductScreenshot |
| 80 | + imageLight="https://res.cloudinary.com/dmukukwp6/image/upload/Clean_Shot_2025_12_05_at_14_38_35_2x_908da89b7a.png" |
| 81 | + imageDark="https://res.cloudinary.com/dmukukwp6/image/upload/Clean_Shot_2025_12_05_at_14_38_35_2x_908da89b7a.png" |
| 82 | + alt="Workflow monitoring and metrics" |
| 83 | + classes="rounded" |
| 84 | +/> |
| 85 | + |
| 86 | +### Be mindful of costs and rate limits |
| 87 | + |
| 88 | +PostHog plans to price Workflows based on the number of real-time destinations and monthly messages after beta. Design workflows to minimize unnecessary messages. For example, avoid sending multiple messages to the same user around the same event, and use batching or deduplication logic where possible. |
| 89 | + |
| 90 | +Clean up unused/outdated workflows to reduce unnecessary triggers and costs. |
| 91 | + |
| 92 | +## Maintainability |
| 93 | + |
| 94 | +### Plan for maintainability: naming, versioning, cleanup |
| 95 | + |
| 96 | +Give workflows descriptive names like `welcome_email_on_signup`, `drip_7_day_followup`, etc. Avoid ambiguous names like `workflow1`. Version your workflows when you make significant logic changes, or at least document changes in a changelog, so you know which version ran when. |
| 97 | + |
| 98 | +When a workflow becomes obsolete (e.g. onboarding process changed, or a campaign ended), archive or delete it to avoid accidental triggering and reduce maintenance burden. |
| 99 | + |
| 100 | +### Document workflows: what they do, why they exist, who owns them |
| 101 | + |
| 102 | +For each workflow, maintain a short description: what triggers it, what it does, expected behavior, and owner/maintainer. Document assumptions (e.g. “this workflow only runs for paid users”, “email template X must exist”, “delay step must be at least 24h”). Onboard new team members with a “workflow map,” a high-level overview of all active workflows and their purposes. |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | + |
| 109 | + |
0 commit comments