Skip to main content

Notifications Send Blaster

What is the 'Notifications Send Blaster' (NSB)?

The Notifications Send Blaster is a rake task useful for sending one-time notifications to student users.

We have used this task to send an in-app notification to ~55M users over the course of a few hours, but ideally user groups would be maximum 3M ids. If you need to send to a larger subset of users, ask the notifications team.

When to use

You want to send a notification, one time, to a large group of student users.

Example Use Cases

Development

Sending an In-app Notification Blast

  1. Read through the NSB write-up to prepare your user list or see example user queries for usage in the rake task.
  2. Add NSS config file: See example PR or see NSS Example Configs
  3. Add in-app notification template: example PR
  4. Generate your new notification locally! See 'Useful Commands'.
  5. Verify in-app notification looks correct on the frontend.
  6. Get blastin!

NSS Example Configs

You can see more NSS configs in the notification repo including our sample config.

The following is the simplest configuration required to send an in-app notification:

notification_name: tos_update
notification_version: v1
skip_preference_check: true
channels:
in-app:
enabled: true

If your in-app blast has a notification preference associated with it, you can check it automatically by adding the notification preference tag to field notification_preference_name.

Running the NSB task

Get blastin!

Running the Deployer Command with CSV Files

Make sure to use the right Deployer environment with the right -notifications-scratch bucket, else the task will fail.

CONFIRM=false USE_BUCKET_CSV=true GOOGLE_CLOUD_STORAGE_BUCKET=handshake-production-notifications-scratch GOOGLE_CLOUD_STORAGE_PATH=000000000000.csv bundle exec rails "notifications:send_notifications['notification_name=example_notification&notification_version=1']"

Blasting a TOS Update

CONFIRM=false USER_IDS=1,2,3 bundle exec rails "notifications:send_notifications[notification_name=example_notification&notification_version=1"

Blasting a Showcased Feed Post

Note: feed_content_post_recommendation works in ONE locale per blast. So if the content_text is in US english, it will only send to users in US english.

CONFIRM=false USER_IDS=1,2,3 bundle exec rails "notifications:send_notifications['notification_name=feed_content_post_recommendation&notification_version=1&attributes[content_post_id]=1&attributes[content_text]=You can use emojis or single quotations, as long as it’s this type 👀 other marks will break the inline deployer command!']"

Expected Output

At this point, the rake task has been run, but that does NOT mean that the blast was successful.

CONFIRM=false USER_IDS=1,2,3 bundle exec rails "notifications:send_notifications[notification_name=example_notification&notification_version=1"
[IdentityCache] Missing CAS support in cache backend ActiveSupport::Cache::RedisCacheStore which is needed for cache consistency
I, [2024-03-28T23:04:49.635883 #113869] INFO -- : LaunchDarkly disabled!
I, [2024-03-28T23:04:49.636034 #113869] INFO -- : LaunchDarkly disabled!
D, [2024-03-28T23:04:49.658803 #113869] DEBUG -- : Attempting to use Pubsub Emulator at localhost:8087...
D, [2024-03-28T23:04:49.662827 #113869] DEBUG -- : Pubsub connected in development
I, [2024-04-01T19:06:59.539075 #50285] INFO -- : {"notification_name"=>"example_notification", "notification_version"=>"1"}
I, [2024-04-01T19:06:59.539203 #50285] INFO -- : notification_name: example_notification
I, [2024-04-01T19:06:59.539259 #50285] INFO -- : notification_version: 1
I, [2024-04-01T19:06:59.539422 #50285] INFO -- : user_ids: 3
I, [2024-04-01T19:06:59.539501 #50285] INFO -- : Sending notifications to: 3 users
I, [2024-04-01T19:06:59.543977 #50285] INFO -- : Batch 1 sent
I, [2024-04-01T19:06:59.544345 #50285] INFO -- : Send Notifications task finished (workers running asynchronously)

Verify Blast records were generated within NDS

In order to verify blast success, check to see if records were created in NDS.

For in-app:

SELECT * 
FROM `notifications_data_service.in_app_notifications` i
JOIN `notifications_data_service.notifications` n
ON n.notification_id = p.notification_id
WHERE n.notification_name = 'uk_live_rent_free_campaign'

For push:

SELECT * 
FROM `notifications_data_service.push_notifications` p
JOIN `notifications_data_service.notifications` n
ON n.notification_id = p.notification_id
WHERE n.notification_name = 'uk_live_rent_free_campaign'

Remember: this count may different from the total # of ids you provided in the NSB blast. After blast-off, we check user preferences, rejecting requests if the preference is disabled. Many users turn off marketing preferences in particular.

Useful Commands

Here are a few useful commands to generate and view your notification on the handshake app prior to sending it with the blaster:

Example User Queries

  • Query for US users active in last 90 days:
SELECT Users.id
FROM `handshake-production.handshake.users` as Users
WHERE Users.user_type = 'Students'
AND Users.status = 'active'
AND Users.last_logged_in between (TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)) and CURRENT_TIMESTAMP()
ORDER BY id
  • Query for all UK Students:
SELECT Users.id
FROM `handshake-eu-production.handshake.users` as Users
JOIN `handshake-eu-production.handshake.schools` as Schools
ON Users.institution_id = Schools.id
WHERE user_type = 'Students'
AND Schools.region = 'UK'
ORDER BY id

Example Notification Queries

  • Query for push campaign success
    • By 'success', we mean how many push notifications we requested were actually created, NOT whether they were opened.
    • Replace ${notification_name} with the name of template
  SELECT countif(p.failed_at is not null) fail_count, countif(p.sent_at is not null) send_count, countif(p.sent_at is not null)/count(*) 
FROM `notifications_data_service.push_notifications` p
JOIN `notifications_data_service.notifications` n
ON n.notification_id = p.notification_id
WHERE n.notification_name = '${notification_name}'
SELECT COUNT(*) 
FROM `handshake-eu-production.handshake_derived.lifecycle_communication_messages`
WHERE channel = 'push'
AND tag = 'uk_live_rent_free_campaign'
AND first_clicked_at is not null
  • CAUTION: The following query should ONLY be used while testing. It pulls from segment, so it is faster than lcm, which runs in incremental mode (only processing events related to messages SENT in the past 30 day) every two hours and "full-refresh" mode weekly. If you are engaging with an old notification before the weekly run, you may recieve stale stats for the notification.
  • Replace uk_live_rent_free_campaign with the name of template, as well as time_stamp
  SELECT properties, current_user_id
FROM `segment.all_segment_events`
WHERE event_name = 'push_notification_opened'
AND time_stamp >= '2024-10-17'
AND (JSON_VALUE(properties, '$.type') = 'uk_live_rent_free_campaign' OR JSON_VALUE(properties, '$.category') = 'uk_live_rent_free_campaign')
  • Query for push campaign open rates (iOS only)
    • For Android, replace category with type
    • Replace ${notification_name} with the name of template, as well as time_stamp
  SELECT properties, current_user_id
FROM `segment.all_segment_events`
WHERE event_name = 'push_notification_opened'
AND time_stamp >= '2024-10-17'
AND JSON_VALUE(properties, '$.category') = 'uk_live_rent_free_campaign'

Export ids from BigQuery

You can export these ids from BigQuery using EXPORT DATA OPTIONS:

EXPORT DATA
OPTIONS ( uri = 'gs://handshake-production-notifications-scratch/*.csv',
format = 'CSV',
OVERWRITE = TRUE,
header = TRUE) AS (
# YOUR_QUERY_HERE
)
  • If EU, change handshake-production-notifications-scratch to handshake-production-eu-notifications-scratch.

Create an in-app notification

curl -s -v \
-H "Authorization: Bearer apitoken" \
-H "Content-Type: application/json" \
-X POST \
-d '{"notification_name":"example_notification_name", "notification_version":"1", "base_attributes": {}, "items": [{"user_id":125}, {"user_id": 124}]}' \
http://localhost:5550/v1/notifications/batch | jq

Verify users got in-app notification

curl -s -v \
-H "Authorization: Bearer apitoken" \
-H "Content-Type: application/json" \
http://localhost:5551/v1/users/125/notifications/in-app | jq

curl -s -v \
-H "Authorization: Bearer apitoken" \
-H "Content-Type: application/json" \
http://localhost:5551/v1/users/124/notifications/in-app | jq