Skip to content

Stripe events

checkout.session.expired: what it means and what to email

Stripe sends checkout.session.expired when a Checkout page times out unpaid. When it fires, whom you may email, and a short note that asks instead of pushing.

Sent
When a Checkout Session expires unpaid, after 24 hours unless you set it shorter
Stripe emails
No, a recovery email is yours to send
Kicklace
A checkout left and what they were about to spend, if they agreed to promotional email

What it means

Somebody started a Checkout Session and did not pay before it ran out. Stripe calls a Session abandoned once it reaches its expires_at time unpaid. From then on it cannot be opened, and this event is how you find out.

It tells you that a checkout was left. It does not tell you why, and it does not say the person is still interested, so the email that follows is a check-in and not a reminder from a shop.

When Stripe sends it

By default a Checkout Session expires 24 hours after you create it. You can shorten that by setting expires_at yourself, down to a minimum of 30 minutes, to hear about abandonment sooner.

Each Session somebody leaves sends an event of its own, so record when you have emailed a person and do not write to them again for the same cart.

If you enable after_expiration.recovery when you create the Session, the event carries a recovery link. Opening it creates a new Session that copies the expired one, and the link works for 30 days.

Does Stripe email the customer?

No. Stripe gives you the event, the consent result and the recovery link, and the email is yours to send.

Customers must agree to promotional email before you contact them. Checkout can ask for that with consent_collection[promotions]. In this event customer_details.email is the email of the Customer when the Session has one. When it has none, it holds the email typed into Checkout only if the customer agreed to promotional content. If you do not collect that agreement, do not send the email.

The email to send

One short note, about a day after the Session expired, to people who agreed. Ask what got in the way and offer the link. A second email about the same cart is where a check-in turns into chasing.

Subject: Did something get in the way?

Hi {{first_name}},

You got as far as checkout for [your app] and then the page closed. If a question or a payment problem stopped you, reply to this email and I will sort it out.

If you would rather pick up where you left off, this link reopens your cart: [recovery link].

[Your name]

The code to send it yourself is in Stripe checkout.session.expired: email people who left checkout.

Fields worth reading

  • customer_details.email: who to write to. With no Customer on the Session, it is there only if they agreed to promotional email.
  • consent.promotions: opt_in when they agreed.
  • after_expiration.recovery.url and after_expiration.recovery.expires_at: the link that reopens the cart, and when it stops working.
  • amount_total and currency: what they were about to spend, in the smallest unit of the currency.
  • expires_at: when the Session ran out.
  • customer, client_reference_id and metadata: your own way of finding who it was.
if (event.type === "checkout.session.expired") {
  const session = event.data.object;
  const agreed = session.consent?.promotions === "opt_in";
  const to = session.customer_details?.email;
  const link = session.after_expiration?.recovery?.url;
}

The Stripe CLI's stripe trigger does not list this event. To see one, create a Session in a sandbox and expire it through the API.

What Kicklace does

With Stripe connected, the event lands on the person as a checkout left, checkout_abandoned, with the amount they were about to spend, but only when the Session's consent.promotions is opt_in. Kicklace keeps the words Checkout shows beside that box, “Keep me updated with news and personalized offers.”, with the event. A Session that expired without that answer is answered and ignored, even with an email on it, because Stripe's rule is that nobody gets a recovery email without agreeing first. Kicklace also needs to know who it was: if Stripe left out the email and names no customer, there is nobody to put it on.

A side road on your Lifecycle map can start from checkout_abandoned once one has arrived. Turn on consent_collection[promotions] for the Sessions you want followed up, or none will arrive. If you ask for the agreement on your own page before Checkout, Kicklace does not see it. Nothing sends until you switch the side road on, and Kicklace shows who would have got it over the last 30 days first.

Write yours from your URL. Paste your site's address into the welcome email generator and it writes your first emails in your site's voice, ready to copy, with no sign-up. The checkout note is one you add on the map, where Write for me drafts it in your voice.

Sources

Checked against Stripe’s docs on .

Free up to 1,000 contacts.

Join the journey

We're building Kicklace so you can get back to building your own product. We'll email you when there's something new worth showing.