Skip to main content

Monitoring

Joryio's Monitoring section lets you set up alerts that fire when something you care about crosses a threshold - your inbound API traffic, the webhooks Joryio delivers from your Journeys, the customer events your app and SDK track, or your deliverability rates (bounces, complaints, delivery). Each alert watches a single metric, evaluates it every minute, and notifies you by email or webhook when it transitions from healthy to triggered.

Open Settings → Logs & Monitoring in the dashboard to manage alerts and audit past fires.

The Logs & Monitoring hub​

Monitoring lives inside the unified Logs & Monitoring hub, reached from a single sidebar entry. The hub's left rail groups four areas:

AreaWhat it shows
AlertsEvery alert rule in your workspace, its runtime status, and quick actions (snooze / pause / edit / delete / duplicate).
HistoryAppend-only log of every time an alert transitioned to or from a firing state. Used for post-incident review.
Error logsDelivery and processing errors across channels, for debugging failed sends.
AuditAdmin actions, delivery errors, and authentication events - see Audit Log.

This page covers Alerts and History (the alerting feature). Fires and resolves also land in the bell in the dashboard header, with read state per person (see Notifications), so you don't have to keep the hub open to notice an incident.

Creating an alert​

Click + New alert on the Alerts page. The New Alert form is a 3-step wizard with a sticky left rail tracking your progress:

StepTitleWhat you set
1Metric - What to watchPick a quick-start template (or build your own), name the alert, then choose the direction and metric.
2Condition - When it firesChoose absolute vs change comparison, set the threshold, optionally scope the alert, and watch a live preview.
3Notify - Who hears about itReview a summary, pick the notification channel (email or webhook), and set the cooldown + enabled state.

You can click back to any completed step from the rail. Next is gated - you can't advance past step 1 until the alert has a name, and the footer shows a live status pill (Would fire now / Healthy / Paused) from step 2 onward.

Step 1 - Metric​

Start from a template​

Pre-built templates cover the most common scenarios across three groups. Picking one pre-fills every step - you can still tweak anything before saving. Click Clear to reset to a blank build.

Inbound - API calls into Joryio:

TemplateFires when
Integration silent failureTotal calls drop ≥80% vs the previous hour. Catches a deploy that broke your integration.
Auth brokenMore than 100 × 401 Unauthorized responses in 5 minutes. Catches a deploy that invalidated an API key.
Server rejecting payloadsMore than 100 × 5xx responses in 5 minutes. Usually means your request format changed and Joryio can no longer parse it.
Traffic spikeTotal calls go up 200% vs the previous hour. Catches a runaway script or unexpected surge.

Outbound - webhooks Joryio sends from your Journeys:

TemplateFires when
Webhook endpoint failingMore than 50 × 5xx responses on webhook deliveries in 5 minutes. Your endpoint is down or the path no longer exists.
Webhook stopped firingWebhook deliveries drop ≥90% vs the previous hour. Journey paused, audience drained, or the queue is stuck.

Events - funnel drops in your tracked events:

TemplateFires when
Purchase funnel droppurchase_complete events drop ≥50% vs the same day last week.
Add-to-cart dropadd_to_cart events drop ≥30% vs the same hour last week.
Signup dropsignup events drop ≥50% vs the same day last week.
Active user dropUnique users firing events drop ≥40% vs the same day last week.
Why "last week"?

The Events templates compare against the same window last week rather than the immediately-previous window. Customer events have strong weekly (and hourly) seasonality - a Sunday-night dip is normal, not an incident - so comparing to the previous hour would false-alarm constantly. See Compare to below.

Deliverability - message health rates across channels:

TemplateFires when
High bounce rateBounce rate is above 5% over the last 24h. List quality or sender-reputation issue.
High complaint rateComplaint rate is above 0.1% over the last 24h. Stay below ISP spam thresholds.
Low delivery rateDelivery rate drops below 95% over the last 24h. Fewer messages are reaching inboxes.

Basics​

FieldWhat it does
Alert nameRequired. Shown in the dashboard, in the triggered email subject / webhook payload, and in the History log. You can't advance to step 2 until this is filled in.
DescriptionOptional. Shown to teammates browsing alerts and in the email body so on-call knows what the alert is about.

Direction​

Pick which stream the alert watches:

  • Inbound API - counts requests into Joryio's REST API (e.g. your servers calling POST /events).
  • Outbound webhooks - counts webhook deliveries out of Joryio (sent from a webhook node in a User Journey).
  • Events - counts the customer events tracked from your SDK/app as they land in Joryio. This watches the stored event count, not the inbound API call count - the two diverge when Joryio accepts a call but rejects the payload (that case belongs to Inbound API).
  • Deliverability - watches your message health rates (bounce, complaint, delivery, etc.) measured as a percentage of messages sent over a lookback window. It covers every channel that can report the metric, pooled as a send-weighted average: delivery rate over all five channels, unsubscribe rate over email and SMS, bounce and complaint over email, which is the only channel that has them. It used to evaluate email alone, so a workspace sending mostly SMS or push was watching a rate its traffic barely contributed to. Unlike the count-based directions, deliverability is always absolute mode (a threshold on the rate) and has no scope filter - it covers all messages sent from the workspace.

The metric labels below adapt to the direction you pick.

Metric​

Inbound / Outbound:

MetricWhat it measuresWhen to use
Calls / Deliveries by response codeCount of calls filtered to specific HTTP status codes you pick.Error-rate alerts (401, 429, 5xx).
Total calls / deliveriesCount of all calls regardless of status."Did my integration stop firing?" / "Is traffic surging?" alerts.
Requests / Deliveries per secondMean throughput over the evaluation window.Per-key or per-endpoint capacity alerts.

Events:

MetricWhat it measuresWhen to use
Event countCount of a single event (e.g. purchase_complete).The classic funnel-drop alert - pair with Change mode + same-window-last-week.
Total eventsCount of every event tracked across all event names.Catches your SDK going silent entirely (a deploy broke init, the app crashed for a cohort).
Unique usersDistinct users firing the selected event (or any event if no event name is picked).Audience-side issues vs power-user spikes - better than raw count.

Deliverability (always absolute mode, threshold is a percentage; pick a lookback window of 1h / 4h / 24h / 7d):

MetricWhat it measuresWhen to use
Bounce rateBounced ÷ sent.The headline inbox-placement signal - alert above ~2–5%.
Complaint rateSpam complaints ÷ sent.Mailbox providers throttle above ~0.1–0.3% - alert early.
Hard / Soft bounce ratePermanent vs transient bounces ÷ sent.Isolate reputation-damaging hard bounces from transient soft bounces.
Unsubscribe rateUnsubscribes ÷ sent.Content/frequency fatigue.
Delivery rateDelivered ÷ sent.Use the Below operator to fire when delivery drops under a healthy floor (e.g. < 95%).

Each rate above is pooled over the channels that emit it, weighted by how much each channel sent, so one low-volume channel cannot swing the alert on its own.

note

Deliverability alerts need volume to be meaningful: if no messages were sent in the lookback window, the alert never fires (so a delivery rate < 95% alert won't false-alarm on a quiet night).

Response codes (inbound/outbound, when applicable)​

When the metric is by response code, pick which HTTP statuses count. The picker groups codes into:

  • Buckets - 2xx, 4xx, 5xx, or all codes.
  • Success - 200, 201, 202, 204.
  • Client errors - 400, 401, 403, 404, 422, 429.
  • Server errors - 500, 502, 503, 504.

You can mix buckets and specific codes (e.g. "5xx or 429").

Step 2 - Condition​

Compare to​

Two evaluation modes:

ModeBehavior
AbsoluteFires when the metric crosses a fixed value for a sustained window. "More than 100 errors in 5 minutes."
Change over timeFires when the metric increases or decreases by a % (or absolute amount) vs an earlier window. "Calls dropped 80% vs the previous hour."

Absolute mode fields:

  • Above / Below - direction of the threshold.
  • Threshold value - numeric value the metric must cross.
  • For X duration - the metric must stay across the threshold for this entire window before the alert fires. Options: 1m, 5m, 10m, 30m, 1h.

Change mode fields:

  • Increased by / Decreased by - direction of the change.
  • Threshold value - the % or absolute amount of change.
  • % or abs - interpret the threshold as a percentage or absolute count.
  • vs previous X window - the size of the comparison window. Options: 15m, 1h, 4h, 1d, 7d.
  • Compare to - what to compare the current window against (see below). Only shown in Change mode.
Compare to (seasonal comparison)​

In Change mode, the alert can compare the current window against one of four baselines:

OptionCompares current window against…Best for
Typical day like this one (recommended)The median of the same window 7, 14, 21 and 28 days back.Almost everything, and percent-drop alerts in particular. Handles weekly seasonality, and because it is a median, one big day cannot move it.
Immediately previousThe window right before.API/webhook traffic with no strong time-of-day pattern, and short windows on steady traffic.
Same window last weekThe same slot exactly 7 days ago.Weekly seasonality when you want a strict like-for-like day - but it is a single sample.
Multi-day averageThe mean of the same window over the last N days (2-30).Smoothing noisy series where no single day is exceptional.

Why the median matters. The other three all break in the same way: they let one unusual day set the baseline. Compare against yesterday and every Monday looks like a crash after a quiet Sunday. Compare against the same day last week and a campaign, an article or Black Friday on that day makes today look broken. Even the multi-day average is a mean, so one exceptional day lifts the baseline for the whole averaging window - meaning every normal day after a good day reads as a drop.

A median of four same-weekdays has neither problem: the spike is one sample of four, so it cannot move the middle value, and the samples are all the same weekday, so seasonality never enters. A genuine, sustained change in traffic still becomes the new baseline within a couple of weeks.

If a workspace is too young to have two of those four weeks, the alert reports not enough history yet and stays quiet rather than comparing against zero.

Scope (optional)​

Narrow the alert to a specific slice:

  • Inbound - limit by API key (specific bearer token) and/or endpoint (specific route).
  • Outbound - limit by webhook URL. The dropdown is populated from the live webhook nodes in your active and draft Journeys, so you pick a real destination rather than typing a URL.
  • Events - limit by event name. The picker is driven by your workspace's actual event vocabulary (top 200 event names by frequency over the last 30 days, shown with their counts). Leave it on "all events" to count everything; it's disabled when the metric is Total events.

Leave the scope at its "all" default to evaluate the whole workspace.

Live preview​

The footer polls a preview endpoint with your current settings and shows:

  • Would fire now (red) - the current metric value already crosses the threshold. Useful for catching configs that are too sensitive.
  • Healthy (green) - the current value is within the threshold.
  • Paused (gray) - the Enabled toggle (on step 3) is off, so even if it would fire it won't.

The preview never saves anything and never sends a notification. It's just a sanity check.

Step 3 - Notify​

A dark review summary at the top recaps what you're alerting on ("You're alerting on …"), with an Edit link back to step 1.

Channel​

Pick how the alert reaches you when it fires:

Email channel (default):

FieldWhat it does
Email recipientsPick members from your people, or type an outside address and press Enter or comma. Click ✕ to remove. At least one recipient is required. Outside addresses receive nothing until they confirm - see Outside addresses must confirm. A rule created before outside addresses had to confirm shows a banner with Send confirmation (details).
One message is sent per recipient on the healthy → triggered transition. While the alert stays triggered, recipients get a still firing reminder every 4 hours (at most 3 per incident), and one Resolved email when it returns to healthy.

Webhook channel:

FieldWhat it does
Webhook URLRequired. Joryio POSTs a JSON payload here every time the alert fires.
Signing secretOptional. Joryio signs each request with HMAC-SHA256(body) and sends it in the X-Joryio-Signature header so your receiver can verify the call is genuinely from Joryio.

A live payload preview is rendered in a dark code block, populated with the alert name and metric you just configured. The webhook channel POSTs on both transitions (triggered and resolved) so your receiver can match incidents end-to-end. The 4-hourly still-firing reminders are email only. Delivery is retried up to 3 times with exponential backoff. See the Monitoring API reference for the exact payload contract.

Cooldown & enabled​

FieldWhat it does
CooldownMinimum time between re-fires after the metric returns to healthy. Default 10 minutes. Options: 5m, 10m, 30m, 1h.
EnabledToggle. When off, the alert is saved in Paused state - it won't evaluate or fire.

Alert lifecycle​

Once saved, every alert sits in one of four states:

StateVisualMeaning
HealthyTeal pillWatching, no breach.
TriggeredRed pill with pulseThe metric crossed the threshold and the alert fired. Recipients have been notified. The row shows Firing since with the time the incident started.
SnoozedGray pillTemporarily silenced. Will auto-resume to Healthy when the snooze window expires.
PausedGray pillIndefinitely silenced. Will not evaluate or fire until you manually resume.

Evaluation cadence​

The backend evaluator runs every minute (the smallest duration you can pick in the UI is 1 minute, so finer would be wasted CPU).

Each tick, for every enabled alert that's not snoozed or paused:

  1. Query the metric source (inbound API request log, outbound webhook delivery log, or the events table) for the duration window.
  2. Compare the current value to the threshold. In Change mode, also query the comparison window - either the immediately-previous window or the same window 7 days ago.
  3. If it crosses → set status to Triggered, write a firing row to History, notify via the chosen channel.
  4. If it is still triggered and the channel is email → send a still firing reminder when 4 hours have passed since the fire or the previous reminder, at most 3 per incident.
  5. If it was triggered and the value returns to healthy → set status to Healthy, mark the most recent firing row as resolved with a resolvedAt timestamp, and send a Resolved email (email channel) or POST a resolved webhook (webhook channel).

Cooldown semantics​

After a fire, the alert won't re-fire until the cooldown window has elapsed and the metric has crossed back below the threshold and back above it. This avoids paging on every minute-by-minute jitter when a problem is still ongoing.

Snooze vs. pause​

  • Snooze is timed (1 hour, 4 hours, 24 hours, until tomorrow 9am). The alert auto-resumes when the window passes. Use this for "I know about this, ack me out for 4h".
  • Pause is indefinite. The alert stays paused until you manually click Resume. Use this for rules that aren't relevant today (e.g. during a planned maintenance window with no traffic).

You can snooze a single alert from the row's ⋯ kebab menu, or click Snooze all in the red banner when multiple alerts are triggered at once.

Triggered notifications​

Email​

When an email-channel alert fires, every member on the rule and every confirmed outside address gets a message with:

  • The alert name in the subject (prefixed with an alert icon).
  • The current metric value (the one that breached).
  • The threshold that was crossed.
  • The alert description if you set one.
  • A link back to Settings → Logs & Monitoring → Alerts.

While the alert stays triggered, the same recipients get a Still firing reminder every 4 hours, with the time it started firing - at most 3 reminders per incident. When it returns to healthy they get one Resolved email. A new incident (after a resolve) starts the count again.

Alert emails come from Joryio's own notification address, not from your workspace's email provider, so they never use your sending reputation or quota, and they work whether or not you have set up an email provider.

Webhook​

When a webhook-channel alert transitions, Joryio POSTs a JSON payload to your URL on both triggered and resolved. If you set a signing secret, verify the X-Joryio-Signature header (lowercase hex HMAC-SHA256 of the raw body) before trusting the call. The exact payload shape is documented in the Monitoring API reference.

History​

The History page is the audit trail. Every transition (healthy → triggered, triggered → resolved) writes a row.

Each row shows:

  • Time - when the transition happened, with relative time underneath.
  • Alert + state pill - Firing, Resolved, or Snoozed at fire.
  • Metric snapshot - what the metric reached at the moment of the transition, and what the threshold was.
  • Mini sparkline - a small chart of the metric around the transition. Red for firing, teal for resolved, gray for snoozed.
  • Duration - how long the incident lasted (Ongoing for still-firing).
  • Recipients - who got notified, with +N for the remainder. Reads silent in italic if no one was notified (e.g. the alert was snoozed at the moment).

Filters​

Three filters at the top of the page:

  • Alert - show events for a single alert rule.
  • State - Firing now, Resolved, or Snoozed at fire.
  • Period - 24h, 7d, 30d, 90d.

The four stat tiles above the timeline aggregate over the visible (filtered) events:

TileWhat it counts
Firing nowOpen incidents - the metric is still breaching.
Resolved (7d)Incidents that self-healed or were acknowledged in the last 7 days.
Mean time to resolveAverage duration across resolved incidents.
Notifications sentTotal recipients notified across all events in the window.

What gets measured​

The metrics come from three append-only data streams populated automatically.

Inbound API request log​

  • What's in it: Every API-key-authenticated request to the Joryio REST API. Timestamp, organization, workspace, API key prefix, HTTP method, canonical endpoint (e.g. /users/:id), status code, duration.
  • What's NOT in it: Dashboard traffic (JWT-authenticated calls from the Joryio UI), health checks, internal-only routes.

Outbound webhook delivery log​

  • What's in it: Every webhook attempt sent from a User Journey's webhook node. Timestamp, organization, workspace, canvas, URL, response status (or 0 for transport-level errors like timeouts), duration, attempt number.
  • What's NOT in it: Webhooks sent before this feature was deployed (older queued jobs don't carry the necessary tenant metadata; they're soft-skipped by the logger).

Events​

  • What's in it: Every customer event tracked from your SDK/app, by event name and user. This is the same events table the rest of the platform reads.

Logging controls & retention​

Both the inbound API request log and the outbound webhook delivery log are per-organization configurable (managed by Joryio staff in the admin console):

  • Kill switch - each log stream can be toggled on or off independently for an org. When off, no rows are written and metrics for that direction stop updating. Both default to on.
  • Retention - each stream has its own retention window between 7 and 365 days (default 90). Rows are deleted automatically once they exceed their org's retention.

If your alerts suddenly stop evaluating for a direction, check with your Joryio admin that the corresponding log stream is still enabled.

Automatic health alerts (zero-config)​

Beyond the alerts you configure yourself, Joryio continuously watches every workspace for integration breakage - no setup required:

  • Flatline - events were flowing and suddenly stopped entirely (a dead SDK key, a broken deploy, a removed snippet). Raised as critical.
  • Sustained drop - event volume falls far below the workspace's own multi-day baseline. Raised as a warning.
  • Per-event detection - your most significant events (e.g. purchase, page_view) are watched individually, so a single broken funnel step is caught even while total volume looks normal.
  • Message collisions - your own journeys and campaigns are reaching the same people at the same time. Raised as a warning when, over the last 7 days, at least 25% of the people who received a message got two or more on the same day (and at least 50 people received a message). The alert names the share, how many of them were within an hour, and the campaigns or journeys most involved. It clears itself when the share drops back under the threshold. Nothing is blocked. The share and the minimum are yours to change under Settings → Monitoring → Alerts; 25% is the default because an email and a push to the same person on the same day count as a collision, and many programmes do that on purpose.
  • Regulars went quiet - not an alert but the threshold of the home dashboard's "regulars went quiet" idea, kept here next to the collision alert because it is the same kind of knob. The idea shows when the regular customers whose purchase-overdue flag turned on this week number at least the floor (default 25) or the share of your active regulars (default 2%), whichever is larger. Edit both under Settings → Monitoring → Alerts; the dashboard guide describes the card.

When something breaks you'll see a banner on the Monitoring page and an item in the notification bell, and receive an email that includes a short AI diagnosis - what most likely broke and what to check first. The email goes to the account's owners and admins, plus members whose access lets them change settings in that workspace, once per incident. If you've already configured your own Total events or Unique users alert for the workspace, Joryio suppresses the duplicate email - your alert emails its own recipients.

Dismissing: an automatic alert can be dismissed from the banner - that acknowledges this incident and hides it. If the integration recovers and later breaks again, a new alert is raised. Recovery also resolves the alert automatically.

Cooldown & rate-limit safety​

Alerts fire at most once per cooldown window. If a metric stays in breach for hours, you get the first notification and then a still-firing reminder at most every 4 hours (3 at most), not 60 per hour, plus one email when it resolves. The cooldown clock resets when the metric returns to healthy.

If you've snoozed an alert, fires that happen during the snooze still write a History row (so you can see what you missed), but no notification is sent and the row reads silent (snoozed) in the Recipients column.

In a demo workspace whose external connections are closed, alerts are still evaluated and still show in the app - the bell, the alert's status, the History log (the Recipients column reads silent) and the event-tracking banner - but no email or webhook goes out, for alert rules and for the automatic event-tracking detection alike. Once Joryio opens the demo to external connections, alerts notify as usual.

Limitations​

  • Channels: Email and webhook are both supported. There is no native Slack channel - route Joryio webhook alerts into Slack via a Slack incoming webhook, or use email-based incident integrations (e.g. PagerDuty).
  • Per-event detail pages: The View details button on history rows is visible but currently a no-op.