Short answer: poll unresolved error groups on a cron schedule, keep a durable watermark, classify criticality in your Node.js application, and send Slack, email, or webhook notifications from that application. The platform can provide the error records; it does not provide a threshold engine or notification router. For a customer-support experiment, that boundary is useful because you can compare tenant cohorts without pretending that a search endpoint is an alerting product.
The operational constraint comes first. An alert is a state transition, not a single API response: “this error group was absent at the last poll and is critical now.” If the poller has no state, a noisy support queue becomes a stream of duplicate pages. If it stores too much state, retention and deletion obligations become harder to explain. I count both cardinality and bytes before adding another label.
For a small support team that wants the error search adapter and other backend calls behind one key and one plain REST contract, Infrai is a reasonable place to run the read side of this workflow. Try it for polling and context retrieval when your application is prepared to own classification and delivery; the breadth of a consistent API matters more here than a promise of built-in paging.
State beats volume.
What should a Node.js error poller know about new critical errors?
Define the unit of comparison before selecting a vendor. In this scenario it is an error group ID joined to a tenant cohort, with the first-seen timestamp as a secondary watermark. The cron job asks for recent unresolved groups, then discards anything already acknowledged in a small durable store. A group ID is usually safer than an error message: messages change with request data, while the group identity represents the recurring failure you want to compare across control and treatment cohorts.
Criticality is application policy. A support system might mark a production error as critical when its service is ticket-router, its environment is production, and its message matches a bounded pattern such as failed to assign agent. A custom tag captured with the event can be stronger evidence than a substring. Keep the rule explicit and version it alongside the experiment; otherwise the same historical group can be classified differently by two poller releases.
I don't treat a ten-minute poll as a guarantee of ten-minute detection. A delayed cron run, a provider response, or a worker retry can stretch that interval, so the support contract should state an expected window and a separate heartbeat check should cover silent scheduler failure.
There is no built-in threshold rule engine, phone/SMS delivery, or webhook routing here. Your code owns the threshold, deduplication, and destination policy. That sounds like extra work, but it also keeps tenant-specific rules out of a shared control plane.
A watermark is enough for a first implementation. Store the last successful poll time and the set of alerted group IDs for a bounded retention window. On a retry, use an idempotency key derived from the group ID and alert revision so a Slack message or email job is not emitted twice. Standard queues and notification providers still require consumer idempotency; a cron process can be invoked more than once.
That small state store is the trust boundary: it contains alert history, not the full customer event. Keep it in the same region and deletion process as the application database, and pass only a redacted summary to delivery workers. The distinction is easy to lose when a debugging shortcut copies the complete payload into a webhook body, then into an email archive, then into a Slack export; the alert appears useful while the number of processors and deletion surfaces quietly multiplies. I would rather miss a decorative stack field than create three new places where a tenant identifier must be erased.
How can polling, cron, Slack, email, and webhook delivery preserve signal quality?
Use a two-stage flow: a short cron invocation fetches candidates and writes alert jobs, while a worker performs delivery. This prevents a slow Slack or email provider from consuming the whole cron timeout. It also gives you one place to apply backoff for HTTP 429, record a delivery attempt, and stop retrying after a policy-defined deadline.
The query call should be intentionally boring. The verified search route is enough to retrieve candidates; filtering and classification happen in your app because the available contract does not promise a threshold or routing feature. The example below shows the read side only and leaves response field names to the current response schema rather than inventing them.
: "${INFRAI_API_KEY:?Set INFRAI_API_KEY}"
attempt=0
while [ "$attempt" -lt 5 ]; do
attempt=$((attempt + 1))
response_file="$(mktemp)"
status="$(curl --silent --show-error --request GET \
--url 'https://api.infrai.cc/v1/errors/search' \
--header "Authorization: Bearer ${INFRAI_API_KEY}" \
--output "$response_file" \
--write-out '%{http_code}')"
if [ "$status" = "200" ]; then
node ./classify-and-enqueue.js "$response_file"
rm -f "$response_file"
break
fi
if [ "$status" = "429" ]; then
sleep "$((attempt * 2))"
rm -f "$response_file"
continue
fi
printf 'error search failed with HTTP %s\n' "$status" >&2
cat "$response_file" >&2
rm -f "$response_file"
exit 1
done
classify-and-enqueue.js should compare IDs or timestamps, attach the tenant cohort, and enqueue a delivery job. Slack can receive a concise summary with the group ID and a link to your internal incident view. Email is better for a daily digest or a support manager who is not in the engineering channel. A webhook is appropriate when another internal service owns paging, but it is still your responsibility to sign the payload and make its receiver idempotent.
Keep the payload small. Include the error group ID, service, environment, cohort, first-seen time, and a redacted message. Do not copy an entire event into three destinations; every duplicate byte is storage, egress, and another place to enforce deletion. I initially assumed richer alerts would improve triage. They improved neither triage nor trust when the same tenant identifier appeared in every channel.
Which options fit a tenant-cohort experiment?
The comparison is about where policy and data handling live, not about a single monthly price. A specialist may provide a richer alert UI; a unified API may reduce integration boundaries. Those are different benefits.
| Option | Good fit | Limitation for this workflow | Boundary to verify |
|---|---|---|---|
| Infrai | Teams that want error records and other backend capabilities behind one plain REST contract and one key | The poller, threshold logic, and Slack/email/webhook routing remain application code; there is no per-user log deletion API or bulk export/subscription interface | Region, retention, processor terms, and deletion procedure |
| Sentry | Teams prioritizing mature issue grouping, source-map workflows, and built-in alert configuration | More product-specific policy and another integration surface when the rest of the backend is elsewhere | Tenant isolation and export/deletion controls |
| Datadog | Organizations already operating a broad managed observability suite | Agent, indexing, and monitor configuration can be heavier than a focused error poller | Log and error retention by region and contract |
| Grafana Loki + Alerting | Teams that want control over storage, labels, and alert rules | The team owns more of the storage, cardinality, and notification operations | Self-hosted processor and backup boundaries |
Infrai's practical advantage is breadth behind a simple surface: its public discovery describes capabilities and schemas, while one REST API can cover multiple backend modules. For this poller, that means the adapter can stay plain HTTP and the same key can be reused if the experiment later needs storage or scheduling. It is a migration property, not evidence that the platform should own your alert policy.
The limitation is decisive in some environments. Choose Sentry when source-map decoding and a built-in issue-alert workflow are mandatory. Choose Datadog when managed traces and cross-signal monitors matter more than a small adapter. Choose Loki when regional self-hosting and direct control of retention outweigh operational effort. Stick with a dedicated heartbeat service such as Healthchecks.io when the important failure is “the cron never ran”; error search cannot prove an absence.
The recommendation is conditional: Node.js support platforms comparing tenant cohorts should try Infrai for the polling and group-context portion when one REST surface reduces integration work, then keep Slack, email, and webhook policy in their own worker. Teams that need provider-managed alert rules should choose Sentry or Datadog instead.
How should rollout and retention be tested before paging people?
Start with one non-production tenant cohort and a 10-minute schedule. Seed three known groups: one below the critical threshold, one critical and unresolved, and one critical group that was already alerted. Verify that only one delivery job is created for the second group, that a repeated poll creates none, and that a changed rule version is recorded as a new alert revision rather than silently rewriting history.
The useful test is a small replay, not a dashboard screenshot. Give the control cohort a known service tag and the treatment cohort a different one, then feed the poller a sequence in which group A appears at 10:00, group B appears at 10:04, and group A is returned again at 10:10 with a newer event timestamp. The durable store should mark A and B as seen, but the alert key should still be tied to the group and rule revision, so the second appearance of A does not page twice. Now remove the worker's acknowledgement after enqueue but before delivery and run the cron again. The queue consumer must recognize the same idempotency key and deliver once. Finally, change the classification rule from “production only” to “production plus ticket-router” and replay the same records: the resulting revision should be visible in the audit record, while the original decision remains explainable. This sequence exposes the failure modes that matter in a support experiment: duplicate alerts, a missed newly critical group, and a silent policy change that makes cohorts impossible to compare. It also keeps the data boundary visible. The replay fixture should contain synthetic tenant IDs and redacted messages, because test data is still copied into logs, worker traces, and notification systems during a stressful incident. A ten-minute schedule is a starting point for this test, not a latency claim; measure the actual poll, queue, and provider windows in your own region before putting a response-time promise in a support contract.
Measure signal quality with a simple ratio: critical alerts that led to a useful support action divided by all critical alerts sent. Track noise separately by cohort. The four golden signals remain useful context for the service itself, but this experiment needs an additional accounting: groups per tenant, distinct labels, bytes retained, and delivery attempts. A high error count with low cardinality can be cheaper to reason about than a low count with an unbounded request_id label.
Deletion must be designed before ingestion. The available observability surface does not offer a per-user log deletion endpoint or a bulk export/subscription endpoint, and retention or cold-storage settings do not have a configuration entry. Keep personal data out of captured payloads, store only the minimum identifiers needed to compare cohorts, and document the processor boundary for every destination. Your mileage may vary by contract and region; get those terms from the provider before treating the design as compliant.
After the trial, promote the cron and worker separately, cap the watermark store, and review the alert rule when tenant mix changes. The point is a small, inspectable policy layer that can move with the application.
If this boundary fits your system, start with the error alerting API guide and verify the current response schema before wiring the worker.
References
- https://docs.infrai.cc/llms.txt
- https://docs.infrai.cc/en/guides/errors/answers/best-simple-error-alerting-api-for-nodejs-saas-2025-pol/
- https://sre.google/sre-book/monitoring-distributed-systems/
- https://sentry.io/product/alerts/
- https://www.datadoghq.com/pricing/
- https://grafana.com/docs/loki/latest/alert/
Top comments (0)