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_inwhen they agreed.after_expiration.recovery.urlandafter_expiration.recovery.expires_at: the link that reopens the cart, and when it stops working.amount_totalandcurrency: what they were about to spend, in the smallest unit of the currency.expires_at: when the Session ran out.customer,client_reference_idandmetadata: 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.