[iOS] Adding custom context to background and foregound events

Is it possible to attach custom context data to foreground and background events in iOS? The goal would be to inject more information about the state of the view at the point of foregrounding or backgrounding (scroll depth for instance).

Also: Are background and foreground events appended to the Session context? It’s unclear to me from reading the documentation.

1 Like

I’m unsure if you can manually attach them, but for sure you could use global contexts to attach them. You would just need to use a filter Callback to specify that you only want them attached to foreground and background events.

Also: Are background and foreground events appended to the Session context? It’s unclear to me from reading the documentation.

The opposite - contexts get attached to events, rather than vice-versa. The session context will be attached to all events.

Thank you @Colm

Is there a way to capture state in a global context at the point of the event? I would like to add a context that captures scroll depth of a view at the point of backgrounding and foregrounding. Is it possible to modify a global context (updating a scrollDepth variable when the app is about to enter background or foreground for example), or is it set once immutably?

I believe so - it’s late and my fried brain is unable to make a direct link to the relevant section work, but if you scroll down to “Context Generator Callback” in the global contexts section of the docs, you’ll see an example of how to pass in a function.

I believe that function is evaluated when the track method is called. However it might be when it’s sent - I’ll see if someone can answer for certain. :slight_smile:

2 Likes

I confirm, the context is generated as soon as the tracker receive the event through the track method.
So, you can use global context to add a custom context with the scrollDepth information.
Just be sure that it’s thread safe as the context generation inside the tracker can happen asynchronously.

@Alex_Benini To follow up from @PhillipEnglish I have another question regarding the global contexts:

The documentation states that It’s possible to add global contexts at runtime with the method addGlobalContext however, when looking at the code the globalContextGenerators dictionary is not initialized unless we use the setGlobalContextGenerators method of the builder.

Can someone please explain how this works? The way I see it looks like to add runime global contexts we should firstly set the global context context generators on the builder. Should it be empty in that case? Am I missing something? Many thanks

1 Like

Thanks for raising this up. I’ve just done a quick check but it seems you are right. That’s not the expected behaviour and it will be fixed in a future patch.
Meanwhile, I suggest to use the workaround you suggested:

SPTracker *tracker = [SPTracker build:^(id<SPTrackerBuilder> builder) {
        [builder setEmitter:emitter];
        [builder setSubject:subject];
        [builder setAppId:[NSUUID UUID].UUIDString];
        [builder setGlobalContextGenerators:@{}];
    }];
...
[tracker addGlobalContext:staticGC tag:@"tagName"]);
...

Once it has been fixed, the global context will work exactly as stated in the documentation without the need to create an empty dictionary at the tracker builder.

Here the issue I’ve created with the reported bug: https://github.com/snowplow/snowplow-objc-tracker/issues/553

Please, feel free to add any other detail on the issue and let me know if you have any other doubt or question!

Best,
Alex

1 Like

@Alex_Benini Many thanks for this. One more thing I am unsure of regarding this:

Given @Colm has suggested that a a filter callback is used to only specify that this is attached to certain events how exactly is this supposed to work ? At the point of the app being foregrounded/backgrounded, the SPTrackerEvent instance received in the filter callback has a value of eventName - null, yet however the schema is iglu:com.snowplowanalytics.snowplow/application_foreground/jsonschema/1-0-0 - should we be checking against the schema here ?

1 Like

@Alex_Benini @Colm Guys one more thing. Can you suggest or point on whether achieving the following is possible with SnowPlow:

I know that each time a foreground/background event is sent there is a corresponding Index(which essentially is count) value that gets incremented every time within the current session.

Now we also know that we can attach custom context data to this event.

Would it be possible to do something like: whenever a background/foreground event is sent we could include ALL of the previous custom context data fields that were sent in with the previous events. I know that we can do this ourselves where we keep a list, but I am interested in knowing whether the SDK supports this type of functionality.

Essentially our use case would be:

  1. User backgrounds the app
  2. We attach {“customDataKey”: “customDataPoint1”} to global context
  3. SnowPlow sends a background event with {“customDataKey”: “customDataPoint1”}
  4. User backgrounds the app
  5. We attach {“customDataKey”: “customDataPoint2”} to global context
  6. SnowPlow sends a background event with
    [{“customDataKey”: “customDataPoint1”},
    {“customDataKey”: “customDataPoint2”}]

Hope this makes sense.

(btw @PhillipEnglish is my colleague and we’re working on integrating SnowPlow into our project)

Hi @petar

the difference between eventName and schema can be confusing it’s due to the different nature of some events.
Due to a design legacy some events (extending SPPrimitive) have the eventName field (e.g.: SPPageView), instead other events (extending SPSelfDescribing) have the schema field (e.g: SPForeground and SPBackground).

As you correctly guessed, If you want to filter against lifecycle events (foreground/background) you can just compare the schema. In the doc there are some options:

  • Filter Callback
  • Ruleset Provider

Here an example with ruleset provider:

NSString *foreground =
  @"iglu:com.snowplowanalytics.snowplow/application_foreground/jsonschema/*-*-*";
NSString *background = 
  @"iglu:com.snowplowanalytics.snowplow/application_background/jsonschema/*-*-*";

SPSchemaRuleset *ruleset =
  [SPSchemaRuleset rulesetWithAllowedList:@[background, foreground]];
    
SPGlobalContext *rulesetGC =
  [[SPGlobalContext alloc] initWithStaticContexts:<your context> ruleset:ruleset];
1 Like

No, the SDK doesn’t support that as out-of-the-box feature.
At the moment the SDK doesn’t have memory of previous events, contexts or in general internal state. It is something we are working on but not available at the moment.

As you said you can keep a list in the app side. I think this is the cleanest solution.
Otherwise, you can add static contexts attached to lifecycle events before to process the event.
Something like:

  1. You setup the global context able to compute customDataPoint1 on background events.
  2. The user backgrounds the app
  3. The tracker attaches a context with the computed customDataPoint1 at the background event
  4. You add a static global context with the just computed customDataPoint1 on background events.
  5. The user backgrounds the app
  6. The tracker attaches 2 contexts: the new computed customDataPoint2 and the static one you added at point 4: customDataPont1.

The feature hasn’t been designed for these kind of cases but I think it should work.

Let us know how it proceed, we are keen to improve these edge analytics features based on real cases.

Best, Alex

1 Like

@Alex_Benini Much appreciated once again. You’ve all been super helpful :slight_smile:

We have some bandwidth on doing manipulation server-side so in this instance we’re going to be attaching a single context data fields tied up to each event and it will be processed later by our time managing the backend.

I will let you know if we come back to this in the future. What you’ve explained as a solution makes sense and I see how it potentially could work but for now we’ll be sticking with one event - one context data set.

2 Likes

Hi all,

FYI the bug you reported has been fixed in the version 1.6.1

Thanks again for the heads up!

Best,
Alex