Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DPMMA-2506 Smart Campaign Event Scheduling Based on Contact Behavior #13569

Open
wants to merge 19 commits into
base: 5.x
Choose a base branch
from

Conversation

patrykgruszka
Copy link
Member

@patrykgruszka patrykgruszka commented Mar 22, 2024

Q A
Bug fix? (use the a.b branch) [ N ]
New feature/enhancement? (use the a.x branch) [ Y ]
Deprecations? [ N ]
BC breaks? (use the c.x branch) [ N ]
Automated tests included? [ Y ]
Related user documentation PR URL TODO
Related developer documentation PR URL ---
Issue(s) addressed ---

Description:

This pull request enhances campaign system by dynamically optimizing the timing of event execution based on
individual contact behaviors. By analyzing interaction patterns, such as email opens, website visits and form submissions, the system determines the most effective moment to send out marketing communications, thereby increasing the likelihood of
engagement.

This event schedule option is available for Send Email, Marketing Message, Push Contact to Integration and Send a
Webhook

image

How It Works

  1. Interaction Data Retrieval: The system retrieves interaction data for the contact, including email reads, page
    hits and form submissions, to analyze the contact's engagement patterns.
  2. Minimum Interactions Requirement: A contact must have a minimum number of interactions for the system to
    calculate optimal timing. Each interaction type (e.g., email open, website visit) is only counted once per hour. A
    minimum of 5 interactions is required, otherwise the default ranges are used.
  3. Optimal Time Calculation (execute event within 24 hours): Based on the contact's interaction data, the system
    calculates the optimal time for executing a campaign event, considering the contact's historical engagement patterns.
    • If the contact is at that moment within the optimal window, the event will be executed immediately.
    • If the current time is before today's optimal window, the event is scheduled for the first hour of that window.
    • If the current time is after today's optimal window, the event is scheduled for the first hour of the next day's
      optimal window.
  4. Optimal Date Calculation (execute event within 7 days): The system calculates the optimal time as in the previous
    option and additionally determines the best day of the week. By default, a contact can have from 1 to 3 optimal days.
    • If the contact is at that moment within the optimal window, the event will be executed immediately.
    • If the current time and day are before the optimal window, then schedule it for the first optimal hour of the next
      optimal day.

Default Settings for Optimal Timing

When a contact does not have enough interaction data, default settings are used. These can be configured by an
administrator in the Mautic configuration file and are adjusted according to the contact's preferred timezone.

  • Default Optimal Hour Range: 9 AM to 12 PM
  • Default Optimal Days: Tuesday, Wednesday, and Thursday
'peak_interaction_timer_best_default_hour_start' => 9,  // 9 AM
'peak_interaction_timer_best_default_hour_end'   => 12, // 12 PM
'peak_interaction_timer_best_default_days'       => [2, 3, 4], // Tuesday, Wednesday, Thursday

Based on https://blog.hubspot.com/marketing/best-time-to-send-email

Cache and Limits on Interaction Data Retrieval

To optimize performance for large databases, caching is used to store interaction data, reducing the need for frequent
retrieval. The default settings are:

// Keep the cache for 1 month
'peak_interaction_timer_cache_timeout' => 43800,

// Pull only interactions for the last 60 days
'peak_interaction_timer_fetch_interactions_from' => '-60 days',

// Do not pull more than 50 interactions of each type (page hits / email reads)
'peak_interaction_timer_fetch_limit' => 50,

Steps to test this PR:

  1. Open this PR on Gitpod or pull down for testing locally (see docs on testing PRs here)
  2. Add contacts from various timezones with no interaction history to a segment.
  3. Set up a campaign with an email send event, scheduling it for the contact's optimal timing. (Add variant to execute
    event within 24h and a 7d period)
  4. Make some interactions in different times and days than the default. Remember, only one interaction of each type (
    email read and page hit) is counted per hour. By default, 5 interactions are needed for the contact to change the
    execution time.
  5. Create a new campaign with the same event and check if the event execution times are adjusted to the contact's
    activity time.

@patrykgruszka patrykgruszka marked this pull request as draft March 22, 2024 11:30
Copy link

codecov bot commented Mar 22, 2024

Codecov Report

Attention: Patch coverage is 85.62500% with 23 lines in your changes are missing coverage. Please review.

Project coverage is 61.54%. Comparing base (f86c50e) to head (74bab17).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##                5.x   #13569      +/-   ##
============================================
+ Coverage     61.50%   61.54%   +0.03%     
- Complexity    34067    34112      +45     
============================================
  Files          2241     2243       +2     
  Lines        101850   102009     +159     
============================================
+ Hits          62647    62782     +135     
- Misses        39203    39227      +24     
Files Coverage Δ
...aignBundle/Executioner/Scheduler/Mode/Interval.php 99.27% <75.00%> (-0.73%) ⬇️
app/bundles/CampaignBundle/Form/Type/EventType.php 90.36% <90.00%> (-0.05%) ⬇️
...ignBundle/Executioner/Scheduler/EventScheduler.php 81.25% <33.33%> (-2.21%) ⬇️
app/bundles/CampaignBundle/Entity/Event.php 86.06% <44.44%> (-1.17%) ⬇️
...ignBundle/Executioner/Scheduler/Mode/Optimized.php 14.28% <14.28%> (ø)
...ndles/LeadBundle/Services/PeakInteractionTimer.php 95.16% <95.16%> (ø)

... and 1 file with indirect coverage changes

@patrykgruszka patrykgruszka marked this pull request as ready for review March 22, 2024 14:01
@patrykgruszka patrykgruszka added ready-to-test PR's that are ready to test code-review-needed PR's that require a code review before merging campaigns Anything related to campaigns and campaign builder labels Mar 22, 2024
Copy link
Contributor

@tomekkowalczyk tomekkowalczyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@patrykgruszka very good job, extensive tests make analysis easier. Topics that can be addressed

  1. Do we include e-mail opens and website visits, or do we also include form results? I think this is also an important interaction in the system.
  2. Can you add a material based on which the default email sending time values are set?
  3. We could in the future move variables from app/bundles/LeadBundle/Config/config.php to the dashboard configuration
  4. A nice functionality would be to add information about the optimal interaction time of a given user on the contact card. I would see this as a CRON job. We could show data from the cache and write the date of last modification next to it.

@kuzmany kuzmany self-assigned this Apr 8, 2024
@kuzmany
Copy link
Member

kuzmany commented Apr 9, 2024

We also have a feature like that for segmenting emails.
Have you tested its performance with millions of email_stats and page_hit records?
I will look into it in the coming days.
Thank you.

@kuzmany
Copy link
Member

kuzmany commented Apr 10, 2024

@patrykgruszka do you use it already in production?

@patrykgruszka
Copy link
Member Author

patrykgruszka commented Apr 10, 2024

@tomekkowalczyk good idea, I've added the form submissions to the analysed interactions.

@kuzmany I've tested the queries on a large database and it looks good:

0.049 sec in page_hits length > 7 mln
0.019 sec in email_stats length > 18 mln
0.011 sec in form_submissions length > 300k

In summary, it's less than 0.1 sec for a single contact to get the data from the DB. Processing the interactions with PHP will not be time consuming, so we can omit that. Additionally, a cache is applied so that the database data is not loaded every time.
We are not using this on production yet. This functionality can be easily added in the emails to segments.

@kuzmany
Copy link
Member

kuzmany commented Apr 10, 2024

@patrykgruszka We've already done it for segment emails.
Thank you I will review it this week.

Copy link
Contributor

@tomekkowalczyk tomekkowalczyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look ok to me, good job. I tested several scenarios and it seems to work according to the task description.

@patrykgruszka patrykgruszka added pending-test-confirmation PR's that require one test before they can be merged code-review-passed PRs which have passed code review and removed code-review-needed PR's that require a code review before merging labels Apr 15, 2024
@RCheesley
Copy link
Sponsor Member

@patrykgruszka could you take a look at the conflicts on this PR? We will also need some documentation to both add the info about the feature in the email sending section, and the configuration settings for the config page. Looks like an awesome feature and would love to see it in Mautic!

@RCheesley RCheesley added the has-conflicts Pull requests that cannot be merged until conflicts have been resolved label Apr 25, 2024
@patrykgruszka patrykgruszka reopened this Apr 29, 2024
@patrykgruszka patrykgruszka removed the has-conflicts Pull requests that cannot be merged until conflicts have been resolved label Apr 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
campaigns Anything related to campaigns and campaign builder code-review-passed PRs which have passed code review pending-test-confirmation PR's that require one test before they can be merged ready-to-test PR's that are ready to test
Projects
Status: 🥳 Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants