Marketing

Abandoned cart emails in Go

A Go package that records a basket somebody left idle, sends a sequence of reminder emails about it on a schedule the store sets, stops the moment the basket becomes an order, and credits that order to the record. It adds no third-party dependency: the emails go out through whatever email notifier the store installed.

What it does

The engine records abandonment and announces it, and deliberately stops there, because when and how often to write to a shopper about a stale basket is, in the package’s words, “a marketing decision with opt-out obligations attached”. This module is the other half of that decision: it owns the schedule, and the engine owns the channels.

Its clock is its own. The engine calls a cart abandoned when its TTL runs out, thirty days by default, which is the right clock for retention and the wrong one for a reminder. So the module keeps a record of each basket idle past a threshold the store sets in minutes: by default 10 minutes for a basket that reached checkout, where an email was typed, and 30 for one that did not. The engine’s TTL is untouched.

Each record runs the sequence for its kind. By default a checkout gets three emails, an hour, then 20 hours, then 48 hours apart, and a cart two, after two hours and then 24. Every rule is checked again at the moment of sending, against the basket as it is then. The figures keep apart the orders a reminder preceded and the shoppers who came back on their own.

Configuration

Nothing is required. The storefront address can come from Config, which the reference binary fills from STOREFRONT_URL, and everything can be changed on the Marketing › Automations screen, which wins where both say something.

Cart recovery module settings — 3 settings, 0 required
SettingEnvironment variableRequiredWhat it does
StorefrontURL
Storefront address
STOREFRONT_URL No Where the shopper’s basket lives, as an absolute base URL such as https://shop.example.com; the link lands on that plus /cart/<token>. Unset in both places, a reminder carries the cart token and no link, and a bad value stops the module at startup.
checkout
Abandoned checkout recovery
— No The sequence for a basket with an email on it: on or off, the minutes of inactivity before it counts (1 to a week), and up to five steps, each a wait of up to 30 days and an email. Screen only; there is no Config field for it.
cart
Abandoned cart recovery
— No The same, for a basket that never reached checkout. It can be reached only through a signed-in shopper’s verified address. Screen only.

The module reads its Config struct, not the environment. The variable names are the ones the package’s own example or the reference binary uses; in your own main() you choose where each value comes from. Where a setting has a panel label, the admin’s settings drawer can hold it too, and a value typed there wins over Config.

Setting it up

  1. Set up emailInstall an email notifier and set it up under Notifications › Setup Email. Without one that delivers, every reminder is held as no_email_provider rather than written into a log.
  2. Install the modulePass cartrecovery.New to gocommerce.New, as below, or start the reference binary with -recovery and STOREFRONT_URL set.
  3. Check the automationsUnder Marketing › Automations, review the two sequences and the storefront address. The three reminder emails are worded on Notifications › Setup Email, as Checkout recovery #1, #2 and #3.
  4. Watch the basketsOrders › Abandoned checkouts lists each record with its timeline; Marketing › Cart recovery shows the funnel and the recovered revenue.

main.go

import (
	"os"

	"github.com/itswadesh/gocommerce/core"
	cartrecovery "github.com/itswadesh/gocommerce/ext/cart-recovery"
)

app, err := gocommerce.New(cfg,
	cartrecovery.New(cartrecovery.Config{
		StorefrontURL: os.Getenv("STOREFRONT_URL"),
	}),
)

The package doc has no example of its own; this is how the reference binary’s -recovery flag installs it. cfg is your gocommerce.Config. Import path github.com/itswadesh/gocommerce/ext/cart-recovery.

How it works

What it does not do

Read these before an order depends on it. No store is known to run GoCommerce in production yet, so these come from the code, not from anyone’s experience.

FAQ

Questions about the Cart recovery module

When does a basket count as abandoned?

When it has sat untouched for the threshold its kind has: 10 minutes by default for a basket with an email on it, 30 for one without. Each can be set from 1 minute to a week on the automation screen, and the module checks once a minute.

Which email service does it use?

Whichever the store installed as its email notifier. The module hands the engine a notification and the engine delivers it; with no notifier that delivers, nothing is sent and each record says it is waiting for a provider.

Can I change the wording?

Yes. The three reminders are templates on Notifications › Setup Email, Checkout recovery #1, #2 and #3, with the basket’s summary, item count, subtotal, discount code and recovery_url to use. A step names one, and two steps may name the same.

Can staff send a reminder by hand?

Yes, from the basket’s page, with abandonment.contact. A manual send is recorded on the timeline and leaves the sequence where it was. Changing the automation needs abandonment.automate, which managers have by default and staff do not.

Does it text abandoned baskets?

No. A basket carries no phone number, so every step is an email, and the engine’s own SMS notifiers write about order events only.

Source

Everything on this page is read from ext/cart-recovery in the GoCommerce repository, MIT licensed. When this page and the code disagree, the code is right and this page is out of date.

Try it against a store of your own

The backend + admin quick start runs GoCommerce’s API and admin on your own machine, without a storefront. Add this module to it and try it on test orders before a real one depends on it.

Chat on WhatsApp