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 email 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). A bell in the dashboard header surfaces recent fires across the workspace with an unread count, 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 - email/SMS health rates:

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 email/SMS health rates (bounce, complaint, delivery, etc.) measured as a percentage of messages sent over a lookback window. 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%).
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 recipientsPress Enter or comma after typing an address. Click ✕ to remove. At least one recipient is required.
One message is sent per recipient on the healthy → triggered transition. Resolves are not emailed (too noisy for an on-call inbox - resolution is visible in Settings → Logs & Monitoring).

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. Unlike email, the webhook channel POSTs on both transitions (triggered and resolved) so your receiver can match incidents end-to-end. 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 just fired. Recipients have been notified.
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 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 POST a resolved webhook if the channel is webhook).

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 recipient 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.

The email is sent through your workspace's configured email provider (the same one used for campaigns).

No email provider configured

If your workspace has no email provider, the alert still transitions state and writes to History, but no email goes out. Set up an email provider under Settings → Email Configurations before relying on email alerts in production.

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.

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. If you've already configured your own alert covering the same signal, Joryio suppresses the duplicate email.

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'll get one notification - not 60 per hour. 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.

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.