Workflow Automationn8nZapierMakeOperations

What to log in every automation: the 8-field run record

A debuggable automation writes one structured run record per execution with eight fields: a run ID, the idempotency key, the trigger payload, each external call's request and response as a pair, the branch taken, the outcome, and a timestamp. Logging only the error message tells you something broke, not what the run did or whether it is safe to re-run.

Alexey YushkinFounder, GENERAL INFORMATICS2 min read

Most people log the error message and stop there. That tells you something broke. It does not tell you what the run actually did before it broke, or whether you can safely run it again. The fix is to write one structured record per execution with eight fields: a unique run ID, the idempotency key, the trigger payload, each external call's request and response as a pair, the branch the flow took, the final outcome, and a timestamp. Get those eight into a store you control and almost every automation incident becomes a lookup instead of a guess.

The error message is the worst place to start a debug, because it arrives without context. "Request failed with status 500" at 2am tells you nothing about which customer, which lead, which of the three external calls in the flow, or whether the charge went through before the email step died. The run record carries that context on purpose. This is the difference between an automation you can operate and one you can only rebuild when it surprises you.

Why logging the error is not enough

An automation is a small distributed system. A single run might receive a webhook, call your CRM, call an AI model, and send an email. When it fails, the question is never just "did it fail." It is "how far did it get, what side effects already happened, and is it safe to retry." A bare error line answers none of those.

The expensive failures are not the loud ones. They are the runs that half-succeeded. The CRM record got created, then the email step timed out, and the run logged a timeout. Did the customer get the welcome email? You cannot tell from the error. So you either skip the retry and risk a lead with no follow-up, or you retry and risk a duplicate record. Both are wrong half the time. The run record makes that a five-second answer: look up the run, see that the CRM call returned a 201 with a contact id and the email call never fired, retry only the email.

This is also where automations differ from code you wrote yourself. In a no-code or low-code tool you did not write the retry logic, the webhook delivery guarantees, or the timeout behavior. You inherited them. The run record is how you get visibility back into a system whose internals you do not control.

The 8-field run record

Here is the contract. Every run writes one row with these fields, success or failure, to a store outside the automation platform. The point is not the exact names. It is that all eight are present, because each one answers a question you will eventually ask under pressure.

FieldWhat it holdsThe question it answers
Run IDA unique id for this single execution"Which run are we talking about?"
Idempotency keyThe event's stable id, like a Stripe evt_ or a form submission id"Did we already process this exact event?"
Trigger payloadThe raw input that started the run"What did the flow actually receive?"
RequestEach outbound call: endpoint and the body you sent"What did we ask the external system to do?"
ResponseThe status code and body that came back, paired to its request"Did it succeed, and what id did it return?"
Branch takenWhich path the flow chose: filter passed, AI classified as refund, fallback hit"Why did it behave this way?"
OutcomeA normalized status: success, failed-at-step-X, skipped-duplicate"Where do we stand?"
TimestampStart time, and ideally duration"When did this happen and how long did it take?"

Five of these are cheap and obvious. Run ID, trigger payload, outcome, and timestamp are things most platforms already expose. The idempotency key takes one expression to extract. The two that operators almost always skip are request and response, and skipping them is exactly what turns a debug into a guess.

The one field everyone skips: the request and its response, paired

If you log only one thing beyond the error, log the outbound request next to the response it produced, as a pair, keyed to the idempotency key. This is the field that answers the question that actually costs money: did the customer get charged, get the email, get the record, or not.

Here is why the pairing matters. A response of "200 OK" on its own is ambiguous. A 200 from your CRM's create-contact endpoint is good. A 200 from a payment endpoint that actually contains a body of {"status": "declined"} is bad, and the status code alone hid that. You need the request to know what you asked for and the response body to know what really happened. Logged together, keyed to the idempotency key, they let you reconstruct the run's side effects without touching the external systems at all.

This is the same discipline payment systems are built on. Stripe assigns every API request an idempotency key and stores the result, so a repeated request with the same key returns the original result instead of acting twice. For API v1, Stripe treats two requests as the same if they carry the same key within 24 hours. The platform is doing internally what your run record should do externally: remember the request, remember its result, and tie them to a stable key so a repeat is recognizable. You are building a small version of that for the flows you do not control.

One caution. Capture the shape, not the secrets. Store the endpoint, the status, and the id the call returned. Mask card numbers, auth tokens, and full personal records. You want enough to reason about the outcome, not a second copy of your customer database sitting in a spreadsheet.

A worked example: the lead that vanished

Take a flow that mirrors the kind of lead intake pipeline we build for clients. A form submission comes in, an AI step scores and tags the lead, your CRM creates the contact, and an email goes out to the sales rep. You test it once, it works, you ship it.

A week later a rep says a lead they "definitely saw the form for" is not in the CRM. No error fired. Without a run record, you are now reconstructing history from four systems' partial logs. With one, you open your record store, filter by the form submission id, and read the row:

  • Run ID present, timestamp shows it ran Tuesday at 4:12pm.
  • Branch taken: AI classified the lead as "spam" with low confidence.
  • Request to the CRM: never made. Outcome: skipped-spam.

Now you know exactly what happened and why. The lead was real, the classifier was wrong, and the flow skipped the CRM step on purpose. The fix is not in your logging, it is in your confidence threshold or a human review step for low-confidence spam calls. But you only got to that fix in seconds because the record told you the branch the flow took, not just that nothing errored. A flow that logged only errors would have shown a clean run and left you arguing about whether the rep imagined the form.

That branch field earns its place here. Half of automation debugging is not "what broke," it is "why did it choose that." An AI step that routes, a filter that drops, a fallback that fires: log the decision, or you will spend an afternoon proving the flow did something it never did.

Where to write the record, not just the platform's history

Every major tool keeps its own run history, and you should use it for live debugging. n8n stores execution data and lets you open a past execution, inspect each node's input and output, and re-run it. Zapier's Zap History logs the data going in and out of each step, supports Replay to rerun a failed step with the original data, and on the Professional plan Autoreplay will retry a failed action up to five times on its own. Make's History tab shows each module's input and output per execution.

So why write your own record at all? Two reasons the built-in history cannot cover. First, retention. Platform history is pruned on a schedule that varies by plan, so the run you need to investigate may already be gone by the time the question arrives. Second, queryability. Built-in history is a per-run view, not a table you can filter. "Show me every run last month that hit the spam branch" or "every payment call that returned a non-200" is a one-line filter against your own store and effectively impossible against scattered platform history.

The store does not need to be fancy. For low volume, a Google Sheet or an Airtable base with one row per run is enough. For higher volume, a Postgres or SQLite table. The only real test is whether, a month from now, you can filter by run ID, idempotency key, and outcome and get an answer. Add a single step at the end of every flow, on both the success and the failure path, that appends the eight fields. In n8n that is a final node on the main path plus an Error Trigger workflow that writes the same shape on failure. In Zapier and Make it is a final action plus an error handler that logs the run before it ends.

How to add this to a flow you already have

You do not need to rebuild anything. Pick your highest-stakes automation, the one that touches money or leads, and add one logging step at the end of the success path and one in the error path. Have both write the same eight fields to the same store. That alone moves you from "we think it ran" to "we can prove what it did."

Then make the next failure cheaper. The run record pairs naturally with the reliability fixes in why automations silently break: the idempotency key you log is the same key you dedupe on, and the outcome field is what tells your error path whether to retry or skip. We build this record into every workflow automation system we ship, because the cost of adding it is one node and the cost of not having it is an afternoon of forensics every time a flow surprises someone. If you have a flow that has already cost you a confusing debug, send it our way and we will tell you which of the eight fields it is missing.

Frequently Asked Questions

SOURCES & CITATIONS

  1. Idempotent requests Stripe API Referencehttps://docs.stripe.com/api/idempotent_requests
  2. Designing robust and predictable APIs with idempotency Stripehttps://stripe.com/blog/idempotency
  3. Debug and re-run past executions n8n Documentationhttps://docs.n8n.io/workflows/executions/debug/
  4. Replay Zap runs Zapier Helphttps://help.zapier.com/hc/en-us/articles/8496241726989-Replay-Zap-runs

About Alexey Yushkin

Alexey is the founder of GENERAL INFORMATICS LLC. He designs and ships AI and automation systems for businesses and operators across the US.

Related reading

Want this kind of system in your business?

We build practical AI and automation systems for operators. Send us your current workflow and we will show you what to automate first.

Request a Workflow Review