Shorten the next session for a user who keeps stopping early
A user has started three sessions this week and finished none of them, each one stopped around the middle. The plan has a fourth session queued at the same length, and the report that would show the pattern arrives after the week is over. By then the fourth session has been served and stopped too. The right move is a shorter session, ready the next time this user opens the app.
sessions_started_7d- Sessions started in the last seven days
sessions_finished_7d- Sessions finished in the last seven days
days_since_finish- Days since they last finished a session
Shortens the next session when three of this week's starts have no finish, and returns to the planned length once a finish comes through. Which exercises make up the shorter session stays with the plan builder.
from datetime import timedelta
from snowplow_signals import Attribute, Event, StreamAttributeGroup, user_id
workout_started = Event(name="workout_started", vendor="com.example", version="1-0-0")
workout_completed = Event(name="workout_completed", vendor="com.example", version="1-0-0")
sessions_started_7d = Attribute(
name="sessions_started_7d",
type="int32",
events=[workout_started],
aggregation="counter",
period=timedelta(days=7),
default_value=0,
)
sessions_finished_7d = Attribute(
name="sessions_finished_7d",
type="int32",
events=[workout_completed],
aggregation="counter",
period=timedelta(days=7),
default_value=0,
)
days_since_finish = Attribute(
name="days_since_finish",
type="double",
events=[workout_completed],
aggregation="time_since_last",
time_unit="d",
)
# Users are logged in to train, so the group keys on the user id.
fit_plans_abandoned = StreamAttributeGroup(
name="fit_plans_abandoned",
version=1,
attribute_key=user_id,
owner="you@example.com",
attributes=[sessions_started_7d, sessions_finished_7d, days_since_finish],
)// In the service that builds the user's next session
const user = await signals.getServiceAttributes({
name: "fit_plans_abandoned",
attribute_key: "user_id",
identifier: userId,
});
// { sessions_started_7d: 3, sessions_finished_7d: 0, days_since_finish: 9.4 }
const unfinished = user.sessions_started_7d - user.sessions_finished_7d;
if (unfinished >= 3) {
planBuilder.next({ userId, length: "short" });
}