Make the save offer while they are still deciding
A subscriber who read most days has opened two articles this month, and tonight they are on the cancel page. Canceling is becoming one click in more markets, so a save email after the cancellation arrives after the decision. The offer has to sit on this page, beside the cancel button, while they are still deciding.
visits_30d- Separate visits in the last 30 days
cancel_page_views_1h- Times the cancel page was opened in the last hour
Shows a pause or a discounted renewal on the cancel page itself when a subscriber's visits have dropped this month, and tells your CRM which offer they saw so the follow-up matches.
from datetime import timedelta
from snowplow_signals import (
Attribute, AtomicProperty, Criteria, Criterion, Event, StreamAttributeGroup, user_id,
)
page_view = Event(name="page_view", vendor="com.snowplowanalytics.snowplow", version="1-0-0")
visits_30d = Attribute(
name="visits_30d",
type="int32",
events=[page_view],
aggregation="approx_count_distinct",
property=AtomicProperty(name="domain_sessionid"),
period=timedelta(days=30),
)
cancel_page_views_1h = Attribute(
name="cancel_page_views_1h",
type="int32",
events=[page_view],
aggregation="counter",
criteria=Criteria(all=[
Criterion.like(AtomicProperty(name="page_url"), "%/account/cancel%"),
]),
period=timedelta(hours=1),
default_value=0,
)
# Subscribers are logged in, so this group keys on the user id.
retention_save = StreamAttributeGroup(
name="retention_save",
version=1,
attribute_key=user_id,
owner="you@example.com",
attributes=[visits_30d, cancel_page_views_1h],
)// In the code that renders the cancel page
const subscriber = await signals.getServiceAttributes({
name: "retention_save",
attribute_key: "user_id",
identifier: userId,
});
// { visits_30d: 3, cancel_page_views_1h: 1 }
if (subscriber.cancel_page_views_1h > 0 && subscriber.visits_30d <= 4) {
paywall.show({
offer: "pause_or_discount",
headline: "Pause for a month instead",
});
}