Posting to google analytics from Delphi app - delphi

I've been tasked with sending data from a Delphi 2010 desktop app to google analytics so we can track which parts of the program are being used more heavily (or used at all). I'm using Indy to post, and the post seems to be generating a valid response, but I'm not seeing anything on the Google Analytics side. I'm totally new to Google Analytics, so might be doing something wrong with what I'm posting or in how I am viewing it. I did create an app view in analytics, but don't know if I set it up correctly.
Parameters := TStringList.Create;
Parameters.Add('v=1'); //Version
Parameters.Add('&tid=UA-nnnnnnnn-n'); //Tracking ID
Parameters.Add('&cid=555'); //
Parameters.Add('&t=test2'); // Screenview hit type.
Parameters.Add('&an=AppName'); // App name
Parameters.Add('&av=' + sAppVersion); // App version
Parameters.Add('&aid=12345'); // App Id
Parameters.Add('&aiid=InstallerID'); // App Installer Id
IdHTTP.Post('https://www.google-analytics.com/collect',Parameters);
Result:= IdHTTP.ResponseText;
I've verified that the tracking ID (replaced with UA-nnnnnnnn-n above) is correct. Would like to know if what I'm submitting is complete and/or if there's something I need to do to see the hit on the GA side. Thanks.

You can use the /debug/collect/ endpoint instead of /collect/ to validate your hits and receive a response containing any possible errors for each request.

Solved this one. Turned out to be three things that needed help:
When manually constructing https parameters, one generally needs an & before each new parameter. When passing parameters in a TStringList with Indy's TIdHTTP.Post, an & before parameters doesn't generate any error that returns, but it also doesn't work. Taking the & out of the parameters.Add fixes this.
To figure out which parameters must be included together, the analytics hit builder provides a way to quickly determine whether a hit is valid or whether there's a missing parameter. (Some parameters are required only in combination.)
(https://ga-dev-tools.appspot.com/hit-builder/)
An incoming hit (even in valid format from the hit builder) can result in no visible results without building a dashboard/widgit or report specifically designed to show the type of hit you are generating. Thus, an existing site that has been configured to count web page views doesn't seem to show app hits or events or types of hits that are different than the existing views are configured for.
Fix them all, and things work.

Related

How to prevent an app redirect on iOS for an URL with query?

we're troubleshooting a problematic scenario involving the Universal Links on iOS.
In a nutshell, we need to make sure the app redirect happens only for the path without a query.
I.e. when the user goes to https://www.example.com/path, we want it to be redirected to an app. However, we have a bunch of complex scripts on the site, triggered by urls like https://www.example.com/path?someparam=1&anotherparam=23, that should be handled via the **browser **(no support for those features in the app yet).
We've have our Domain Association file uploaded, and it has featured the following snippet in the components section:
{"/":"/path"},
This does force the iOS to redirect to our app whenever user clicks a no-query an any application, or scans a QR code.
However, it does also cause a redirect for the links with query (https://www.example.com/path?someparam=1&anotherparam=23)
I've read through the https://developer.apple.com/documentation/bundleresources/applinks on this, and have tried a few tricks:
Insert an exclude block prior to the existing one:
{"/":"/path", "?":"?*", "exclude":true},
{"/":"/path"},
Update the existing block to enforce an empty query on it:
{"/":"/path", "?":""}, // supposed to override the implied "?":"*"
Prepend the existing block with a bit different form of the query pattern (to intercept a specfic param in query):
{"/":"/path", "?":{"someparam":"?*"}, "exclude":true},
{"/":"/path"},
Nothing did help so far - iOS still does redirect the links https://www.example.com/path?someparam=1&anotherparam=23 to the application. I have checked that the file is not cached by our reverse proxy. I have checked that the old file is not being cached by our cloudflare CDN. I have checked that the old file is not being cached by the apple delivery service. I have got a clean iOS device to ensure I don't have the redirect preference cached localy - still redirects.
Is this scenario supported at all? Maybe there is a bug in iOS/Safari implementation?

Azure - App Insights - how to track the logged-in Username in Auth Id?

What is the best-supported approach for tracking logged-in Usernames/Ids in App Insights telemetry?
A User with Username "JonTester1" said some Pages he visited 4 hours ago were really slow. How can I see everything JonTester1 did in App Insights to trouble shoot/know which pages he's referring to?
Seems like User Id in App Insights is some Azure-generated anonymized thing like u7gbh that Azure ties to its own idea of the same user (thru cookie?). It doesn't know about our app's usernames at all.
I've also seen a separate field in App Insights called Auth Id (or user_AuthenticatedId in some spots), which looks to sometimes have the actual username e.g. "JonTester1" filled in - but not always... And while I don't see any mention of this field in the docs, it seems promising. How is our app's code/config supposed to be setting that Auth Id to make sure every App Insights log/telemetry has it set?
Relevant MS docs:
https://learn.microsoft.com/en-us/azure/azure-monitor/app/usage-send-user-context
This looks to just copy one library Telemetry object's User Id into another... no mention of our custom, helpful Username/Id anyway... and most in-the-wild examples I see don't actually look like this, including MS docs own examples in the 3rd link below; they instead hardcode get a new TelemetryClient()
https://learn.microsoft.com/en-us/azure/azure-monitor/app/website-monitoring No mention of consistently tracking a custom Username/Id
https://learn.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics#authenticated-users Shows some different helpful pieces, but still no full example. E.g. it says with only the setAuth... JS function call (still no full example of working client-side JS that tracks User) on the page, you don't need any server-side code for it to track custom User Id across both client-side and server-side telemetry sent to Azure... yet then it also shows explicit code to new up a TelemetryClient() server-side to track User Id (in the Global.asax.cs or where?)... so you do need both?
Similar SO questions, but don't connect the dots/show a full solution:
Azure Insights telemetry not showing Auth ID on all transactions
Application Insights - Tracking user and session across schemas
How is Application insight tracking the User_Id?
Display user ID in the metrics of application Insight
I'm hoping this question and answers can get this more ironed out; hopefully do a better job of documentation than the relevant MS docs...
The first link in your question lists the answer. What it does show you is how to write a custom telemetry initializer. Such an initializer lets you add or overwrite properties that will be send along any telemetry that is being send to App Insights.
Once you add it to the configuration, either in code or the config file (see the docs mentioned earlier in the answer) it will do its work without you needing to create special instances of TelemetryClient. That is why this text of you does not make sense to me:
[…] and most in-the-wild examples I see don't actually look like this, including MS docs own examples in the 3rd link below; they instead hardcode get a new TelemetryClient()
You can either overwrite the value of UserId or overwrite AuthenticatedUserId in your initializer. You can modify the code given in the docs like this:
if (requestTelemetry != null && !string.IsNullOrEmpty(requestTelemetry.Context.User.Id) &&
(string.IsNullOrEmpty(telemetry.Context.User.Id) || string.IsNullOrEmpty(telemetry.Context.Session.Id)))
{
// Set the user id on the Application Insights telemetry item.
telemetry.Context.User.AuthenticatedUserId = HttpContext.Current.User.Identity.Name;
}
You can then see the Auth Id and User Id by going to your AI resource -> Search and click an item. Make sure to press "Show All" first, otherwise the field is not displayed.
Auth Id in the screenshot below is set to the user id from the database in our example:
We access the server from azure functions as well so we set the user id server side as well since there is no client involved in such scenarios.
There is no harm in settting it in both places, javascript and server side via an initializer. That way you cover all scenario's.
You can also manually add user id to app insights by
appInsights.setAuthenticatedUserContext(userId);
See App Insights Authenticated users

Revulytics data not showing in Dashboard

I am using Revulytics SDK to track feature usage and came across the below problem.
I am sending feature usage after properly setting up the SDK configuration etc, using the EventTrack() method like this:
GenericReturn grTest = telemetryObj.EventTrack("FeatureUsage", textBoxName.Text.ToString(), null, false);
This returns OK and usually, I can see the usage data in the dashboard. However, after multiple tests, the data I am sending does not show up on the dashboard.
Can anyone hint me how to debug this? Thanks for any help!
I hit a similar issue when first working with this SDK.
I was able to address this as soon as I understood the following:
There are event quotas for the incoming events;
Event names are used for making the distinction.
So when I was sending dummy test data, it made it there, but when I sent some demo data for stakeholders, it was not showing up.
I think the same happens here. You're getting the event name form textbox.text... Pretty sure that varies every time you run the code.
Here are the things to keep in mind when testing your code:
the server has a mechanism to discard / consider events;
implicitly, it allows first xx events depending on the quota;
if you are sending more than xx events, they will not show up in reports.
So, you must control which events to discard and which to consider (there are a couple of levels you can configure, and based of them you can get the events in various types of reports).
Find the "Tracked Events Whitelist Management". You will be able to control these things form there.
This blog helped me (it is not SDK documentation): https://www.revulytics.com/blog/getting-started-with-usage-intelligence-part2-event-tracking
Good luck!

Paypal Payments Standard not returning payment variables on iPad

I have just finished developing a website using Paypal Payments Standard, and all is working just fine in most computers, but paypal does not return any payment variables on iPad (and maybe other devices).
I created my own cart, and use the Buy Now functionality to pay for the entire order.
The Buy Now form sets the RETURN variable to the cart page, and the RM variable is set to 2, which should post the variables back to the cart page.
When the payment is complete, the cart page checks for posted payment variables and logs them into the database.
As said, this works perfectly on most computers.
On iPad, though, the user returns to the cart page, but no payment variables are posted. This is just the same when changing the RM variable to 1, which should send the variables as GET parameters.
You can see the code and working website at: http://unameit.ch/
This isn't exactly an answer to your problem, but would solve the issue and would be better for you anyway.
Using your return URL is not a good way to get data into your database because even with Auto-Return enabled there is no guarantee the user would make it back to your return URL. In such cases, that code would never run and the data would never make it into your database.
Instead, what you should use is IPN. IPN will be triggered regardless of whether or not the user makes it back to your site. It's very similar to PDT except that instead of POSTing data back to the return URL it POSTs it to a separate listener script apart from your checkout pages. It happens in real-time so the result would be the same as what you're trying to do now, but it would always work regardless of whether or not the user made it back to your site, and you wouldn't have to worry about issues like you're running into here with the iPad transactions.
I highly recommend you do it this way or you'll find that you're missing order data in your database even if you end up getting this particular problem resolved.
I have had the same issue with the manual callback and have been speaking to PayPal tech support. They have agreed that there is a bug with this working on a mobile/tablet devices. Basically, if you go to the mobile PayPal site to make the payment, you won't get any data POSTed back to your return URL:
They have told us to use the ExpressCheckoutAPI instead:
"Yes the ExpressCheckout works without any issues on all platforms.
As a mater of fact I found that the mobileWPS checkout is Wraped around the
ExpressCheckout and this is the reason why your data is chopped off.
Some of the data is lost in translation from WPS to EC."
Sorry that this isn't a answer but at least we know that PayPal know it's a bug.

Preventing double HTTP POST

I have made a little app for signing up for an event. User input their data and click "sign me in".
Now sometimes people are double in the database, the exact same data that got inserted 2 times very quickly after each other. This can only mean someone clicked the button twice, which caused two posts to happen.
This is common web problem, as credit card apps and forum apps often say: "Clicking once is enough!".
I guess you could solve it by checking for the exact same data to see if the post is unique, but I wonder if there are other methods.
This ofcourse does not count for ASP.NET webforms, because POST doesn't matter as much.
While JavaScript solutions can disable the submit button after it has been clicked, this will have no effect on those people who have JavaScript disabled. You should always make things work correctly without JavaScript before adding it in, otherwise there's no point as users will still be able to bypass the checks by just disabling JavaScript.
If the page where the form appears is dynamically generated, you can add a hidden field which contains some sort of sequence number, a hash, or anything unique. Then you have some server-side validation that will check if a request with that unique value has already come in. When the user submits the form, the unique value is checked against a list of "used" values. If it exists in the list, it's a dupe request and can be discarded. If it doesn't exist, then add it to the list and process as normal. As long as you make sure the value is unique, this guarantees the same form cannot be submitted twice.
Of course, if the page the form is on is not dynamically generated, then you'll need to do it the hard way on the server-side to check that the same information has not already been submitted.
Most of the answers so far have been client-side. On the server-side, you can generate a hidden field with a GUID when you first produce the form, and then record that GUID as a submitted form when the post is received. Check it before doing any more processing.
Whenever a page is requested from the server , generate a unique requestToken , save it in server side,mark status as NOT Processed and pass it along with the current requested page. Now whenever a page submit happens , get the requestToken from the "POST"ed data and check the status and save the data or take alternate action.
Most of the banking applications use this technique to prevent double "POST"ing.So this is a time proven & reliable way of preventing double submissions.
A user-side solution is to disable the submission button via Javascript after the first click.
It has drawbacks, but I see it often used on e-commerce websites.
But, it won't never replace a real server-side validation.
Client side techniques are useful, but you may want to couple it with some server side techniques.
One way to do this is to include a unique token in the form (e.g. a GUID or similar), so that when you come to process the form you can check to see whether the token has already been used, preventing a double submission.
In your case, if you have a table with event visitors, you might include this token as a column.
A client-only solution won't be enough, as stated in many of the answers here. You need to go with a server-side fail-safe.
An often overlooked reason that disabling the submit button doesn't work is, the user can simply refresh the submit target (and click OK on the "are you sure you want to resubmit the POST data?" dialog). Or even, some browsers may implicitly reload the submitted page when you try to save the page to disk (for example, you're trying to save a hard-copy of an order confirmation).
Almost no one has js disabled.
Think about coding your e-commerce website for the 70 year old woman who double clicks every link and button.
All you want to do is add a javascript to prevent her clicking "Order Now" twice.
Yes - check this at the server side too "be defensive" - but don't code for that case. But for the sake of a better UI do it on the client side too.
Here are some scripts that I found:
//
// prevent double-click on submit
//
jQuery('input[type=submit]').click(function(){
if(jQuery.data(this, 'clicked')){
return false;
}
else{
jQuery.data(this, 'clicked', true);
return true;
}
});
and
// Find ALL <form> tags on your page
$('form').submit(function(){
// On submit disable its submit button
$('input[type=submit]', this).attr('disabled', 'disabled');
});
None of the solutions address a load-balance server.
If you have some load balancer, send a UUID (or any type of unique number) to the server to store and read again will not work well if the server is not aware of other servers, because each request could be processed by a different server in a stateless environment. These servers need to read/write to the same place.
If you have multiple servers you will need to have some shared cache (like a Redis) among the servers to read/write the unique value in the same place (what could be an over-engineering solution, but works).
Client side alteration is a common technique:
Disable submit button
Change the screen to a "please wait" screen
If the form was modal, changing the screen back to their usual process (this has the benefit of making things look really slick)
But it's not perfect. It all relies on JS being available and if that's not the case, without back-end duplication detection, you'll get duplicates still.
So my advice is to develop some sort of detection behind the scenes and then improve your form to stop people with JS being able to double-submit.
You can track the number of times the form's been submitted and compare it to the number of unique visits to the page with the form on it in the session.
Beside the many good techniques already mentioned, another simple server-side method, that has the drawback of requiring a session, is to have a session variable that is switched off on the first submit.

Resources