Send the reminder when their usual hour has passed, to them only
A user finishes a workout around seven most evenings. Tonight it is eight and the app has recorded nothing. The daily reminder went out at six to everyone, so it reached this user an hour before they would have trained anyway, and reached the lunchtime crowd hours after they had finished. The reminder that keeps this streak is the one that goes to this user once their usual hour has passed with no workout, and to nobody else.
usual_workout_hour_30d- The hour of day they most often finish a workout, over the last 30 days
workouts_1d- Workouts finished in the last day
Sends the reminder to a user whose usual hour has passed with no workout finished today, and skips the user whose usual hour is still ahead of them. The message and the channel stay with your messaging tool.
from datetime import timedelta
from snowplow_signals import Attribute, AtomicProperty, Event, StreamAttributeGroup, user_id
workout_completed = Event(name="workout_completed", vendor="com.example", version="1-0-0")
usual_workout_hour_30d = Attribute(
name="usual_workout_hour_30d",
type="int32",
events=[workout_completed],
aggregation="most_frequent",
property=AtomicProperty(name="derived_tstamp", date_part="hour_of_day"),
period=timedelta(days=30),
)
workouts_1d = Attribute(
name="workouts_1d",
type="int32",
events=[workout_completed],
aggregation="counter",
period=timedelta(days=1),
default_value=0,
)
# Users are signed in to the app, so this group keys on the user id.
fit_reminders_evening = StreamAttributeGroup(
name="fit_reminders_evening",
version=1,
attribute_key=user_id,
owner="you@example.com",
attributes=[usual_workout_hour_30d, workouts_1d],
)// In the job that decides tonight's reminder sends, for each user
const user = await signals.getServiceAttributes({
name: "fit_reminders_evening",
attribute_key: "user_id",
identifier: userId,
});
// { usual_workout_hour_30d: 19, workouts_1d: 0 }
// The hour comes from the event timestamp, which is UTC, so compare in UTC.
const hourNow = new Date().getUTCHours();
if (hourNow > user.usual_workout_hour_30d && user.workouts_1d === 0) {
push.send({ userId, template: "usual_time_nudge" });
}