It seems my base configuration of GATracker is working because I am able to see my device in the real-time section. However, even after a day or so of firing events via:
- (BOOL)send:(NSString *)trackType params:(NSDictionary *)parameters
I have not seen any events under Engagement > Events > Overview.
I have verified:
I can see traffic in the real-time pane ensuring base functionality
the tracker object is non-nil when using above method
the return value is YES for above method (i.e. it think's it was successfully queued at some point to send)
I even implemented the dispatch call on [GAI sharedInstance] as a sanity check to ensure the events were getting flushed
I've heard reports the b3/b4 version of the 2.0 SDK have had issues sending events but not seeing any at all seems very unusual.
Thanks!
Google Analytics and Mixpanel are different tools and have different ways for sending data.
For Google Analytics events have only 4 fields:
Category (string)
Action (string)
Label (string)
Value (number)
Similarly Pageviews are another type of hit, but they only have 1 field, that is the page url. On mobile apps this is renamed to view instead but it works almost the same way.
These fields have names for reference but you can actually use them for whatever you want. You will be able to drill down from one to the other in the interface.
You can also "add" more fields by using Custom Dimensions/Metrics. If you set a page type custom dimension before the event, that custom dimension/metric will be bound to the event.
Note that it's important to understand and use the right scope for each custom dimension. If you set a session scope for example the only value you will see in GA is the last one set for that specific session, it overrides previous values. You have to configure these through the interface.
I am getting the same issue.
When I use:
[[GAI sharedInstance].defaultTracker sendEventWithCategory:message
withAction:nil
withLabel:nil
withValue:nil];
the result is logged right away.
but, when I use:
[[GAI sharedInstance].defaultTracker send:message params:eventParams];
NO result gets logged at all
Related
I am working with Microsoft bot development framework, using its node.js sdk.
I have been looking for a way to save all the messages of a conversation. I set persistConversationData to true, and tried to access the conversationData using session.conversationData. However, it is empty.
1- Is there a builtin method to access all the messages within a conversation?
2- If persistConversationData is not for that, can anyone please explain its usage.
Thank you so much.
By default, messages will not be persisted by the Microsoft Bot Framework. For stateful operations, you can use the Bot State API the following ways:
Set userData. The persisted data will be available to the same user across different conversations.
Set conversationData. The persisted data will be available to all the users within the same conversation.
Set privateConversationData. The persisted data will be available to the given user in the given conversation.
Set dialogData for storing temporary information in between the steps of a waterfall.
According to the documentation, conversationData is disabled by default. If you want to use it, you have to set persistConversationData to true.
tl;dr You have to take care of persistence for yourself. E.g.
// ...
var bot = new builder.UniversalBot(connector, { persistConversationData: true });
bot.dialog('/', function (session) {
let messages = session.conversationData || [];
messages.push(session.message);
session.conversationData = messages;
});
In Mixpanel you can track each action, like:
[mixpanel track:#"Watched Movie" properties:#{#"Movie ID”:#“1234", #"Movie Name”:#”Rocky 3"}];
And you can set user properties, like:
[mixpanel.people set:#{#"Eye Color":#"Blue"}];
When I want to send an email to a subset of users, I can narrow things down by asking for user properties - Eye Color:Green for instance.
But how do I get a subset of users who have performed a certain action - for instance "Watched Movie" with "Movie Name" "Rocky 3"?
As you have probably noticed, notifications can only be sent based on People Profile Properties. To segment people by events/send notifications based on events, you need to pass event data over to People by adding an extra line of code that sets the event as a people property. As of now, People and Engagement are two separate data sets. We're working on tying these data sets together more tightly, but for the moment they are not seamlessly integrated.
In your example, we would need to fire a people.set as the user watched a movie called Rocky 3
An example of this for iOS would be the following:
[mixpanel.people set:#{#"Rocky 3 Viewed":#"True"}];
Please feel free to write into support#mixpanel.com if you have any other questions!
I'm successfully tracking events and creating people profiles using Mixpanel in Ruby.
I can create an event
tracker.track(123456712,'NewArrival', { gender: 'male', ad_version: 1 })
In this case, when I go into the Mixpanel analytics, I can segment my funnel based on the gender property above I passed in above.
I can also create a person profile:
tracker.people.set(1234560, {
'$first_name' => 'Stacy',
'$last_name' => 'Smith',
'$phone' => '5555555555',
'Favorite Color' => 'blue'
})
In which case I can go into the People tab and see some additional properties about Stacy such as her city and country data, which Mixpanel automatically takes care of.
What I'd like to do is access the city and country data from the funnel builder interface, so that I can see how my conversion funnels vary by geography. However, I can't see anyway to filter based on this data inside the funnel (the built-in properties do not appear).
Is there a way to do this easily? I guess I can implement my own geo-lookup and pass this data as properties, but given Mixpanel already has this this doesn't seem optimal. Thanks in advance.
People Properties are only for use in the People Analytics reports (bottom set of reports in Mixpanel).
Super Properties are what you use for the engagement (i.e. funnel/segmentation) reports.
You need to Register a Super Property at the same time as the People Property in order to have it show up in all reports.
See Mixpanel Documentation on this: https://mixpanel.com/docs/managing-users/managing-user_specific-properties
Similar to the iPhone Facebook app search function, I am implementing search as you type functionality into my application although I have a problem when decoding the data into JSON format.
Basically what happens is because some searches take longer than others, they return at different intervals and this causes some small visual issues when the data is presenting on the screen.
I have set an NSLOG after each decode using NSJSONSerialization for the keyword 'industry'
2013-04-09 23:38:18.941 Project Name [42836:1d03] http://fooWebAddress/json/?method=search&limit=10&q=indus
2013-04-09 23:38:19.776 Project Name [42836:3e07] http://fooWebAddress/json/?method=search&limit=10&q=indu
2013-04-09 23:38:20.352 Project Name [42836:8803] http://fooWebAddress/json/?method=search&limit=10&q=indust
2013-04-09 23:38:21.814 Project Name [42836:4e03] http://fooWebAddress/json/?method=search&limit=10&q=industr
2013-04-09 23:38:23.434 Project Name [42836:8803] http://fooWebAddress/json/?method=search&limit=10&q=ind
2013-04-09 23:38:24.070 Project Name [42836:7503] http://fooWebAddress/json/?method=search&limit=10&q=industry
As you can see it is all out of order.
Does anyone have any way of stopping NSJSONSerialization for the previous connection.
Or possibly any other way to go about this problem?
Steps up to NSJSONSerialization...
NSURLRequest (initwithURL)
NSOperationQueue
NSURLConnection (asynchronous)
NSJSONSerialization
Thanks in advance.
When the user starts typing more text, you could cancel your previous connections and ignore any further delegate callbacks you receive from them. Then make the new request for the current text.
You can do this by maintaining some sort of lastRequest or lastOperation reference. When the user starts typing, call [self.lastRequestOrOperation cancel] and ignore any further notifications from that request with a check like if (request != self.lastRequest) { return; } in whatever callbacks you have.
However this has the problem that if the user keeps typing for a while you are constantly cancelling requests and they may not see any results until they have stopped typing.
A better solution would be to add sequencing so that each request is associated with an increasing sequence ID. You then only parse the result and update the UI when the sequence of the response is higher than the last one you received. If you receive any out-of-band responses from earlier, you just ignore them.
This is a much more complex issue than just being able to cancel the NSJSONSerialization. My suggestion is to use NSFetchedResultsController to populate your table view that shows the search results. Use the search term as one of the predicate variable in the NSFetchRequest attached to NSFetchedResultsController. And then, when you parse the results using NSJSONSerialization, store the results with the search term associated with that request. As soon as the search term changed (which you can detect when the user types more characters), re-create the NSFetchedResultsController and reload your table view. In addition, you can also try to cancel the call to parse the previous results if you launched it using performSelector:withObject:afterDelay. Beware that this cannot be always relied upon as the call may have been initiated by the time you are trying to cancel.
Kinda basic, but you could always maintain an nsdictionary of sub-classed NSURLRequests (sub-classed to provide a tag).
Start request - add request to dicationary with tag = array.count - 1, with key matching tag
Connection returns - is the request the most recent request, if so, parse json
Parse JSON - is the request the most recent request, if so, show results, if not, only display if there are no previous results displayed
Request handling - remove key from dictionary
most recent request = does the dictionary contain an object with a higher key value
Currently what you are doing is, you type each character and calling web-service. Why to call web-service for each letter you type. If user is type continuously, then it will increase the load, so call the web-service only when user stops for a particular interval of time. and then pass that string to call web-service or what ever method you are calling.
[NSObject cancelPerformSelectorsWithTarget:self]; // This will cancel your all req which is going to make when user typing without stopping
[self performSelector:#selector(sendSearchRequest) withObject:searchText afterDelay:0.1f]; // This will pass the string to call a web-service method, on which user hold for some time.
Is there any way to add transactionality to NSUserDefaults? I would need something like the well known begin - commit - revert functions on database handlers, thus I could revert a modification on the user defaults in some cases. Of course other users of this user defaults would be blocked from writing during the transaction.
Note1: synchronize method of the above class does not do this thing because:
according to the doc, it is called from time to time also by the framework
there is no "revert"
Note2: I saw dictionaryRepresentation and registerDefaults with that I could implement my own transaction mechanism (holding a copy of the old defaults in the memory / even saved to a plist during the transaction). But maybe there is a ready solution for this?
My use case:
I have a wizard-like flow of screens where the user can edit some settings on each screen. As of the current implementation these settings are stored immediately in the defaults as the user moves to the next screen of the wizard. Now this wizard can be interrupted by some other events (even the user can choose to exit/cancel the wizard at any screen) and in this case I would like to roll back the modifications.
One possible solution is to defer setting the values until the end of your wizard. This can be easily done for example using a proxy that will record the messages sent to it and then replay them on the real NSUserDefaults. Recording the messages should be pretty simple:
- (void) forwardInvocation: (NSInvocation*) invocation
{
[invocations addObject:invocation];
}
Where invocations is a mutable array. Replaying the messages back is also simple:
- (void) replayOnTarget: (id) target
{
for (NSInvocation *op in invocations)
[op invokeWithTarget:target];
}
This way the wizard does not have to know anything about the transactions. It would get the recording proxy instead of the expected NSUserDefaults instance and send the messages as usual. After the calling code knows the wizard succeeded, it can replay the messages from the proxy on the shared user defaults. (I have added some sample code on GitHub.)
Maybe this is overkill, but since the recording proxy is generic and can be used in other cases, maybe it’s not bad. Same thing can also be done using blocks:
[transaction addObject:[^{
[defaults setObject:… forKey:…];
} copy]];
Where transaction is a mutable array, again. When the wizard succeeds, you would simply iterate over the array and execute the stored blocks.