GA Enhanced Ecommerce Missing Purchase Events - google-analytics

We are sending the purchase events from the server with code like this:
using (var httpClient = new RestClient())
{
httpClient.SendAsync(new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
});
}
But around 15-20% of the events never gets registered in GA.
Google always seem to respond with a GIF and status code 200, so it is hard to tell which events are not processed successfully.
In the beginning we were using the javascript API to send the event, but when we switched to server side, we copied the request it was creating and tried to replicate it with HttpClient.
The request send looks like the following:
https://www.google-analytics.com/collect?v=1&_v=j47&a=817546713&t=event&ni=0&_s=1&
dl=#scheme + host + pathAndQuery#&dp=#path#&dt=#path#&ul=#browser language#&de=#browser encoding#&sd=#bit#&sr=#screen resolution#&vp=#viewable browser area#&cid=#Id taken from the _ga cookie#&je=0&fl=24.0%20r0&ec=Ecommerce&ea=purchase &_u=SCEAAAALI20%25~&jid=&tid=#TrackingId#&gtm=#TagManagerId#&ti=#OrderId#&ta=&
tr=#TotalPrice#&tt=#TotalTax#&ts=#ShippingPrice#&tcc=#VoucherCode# &pa=purchase&cu=#CurrencyCode#&pr1nm=#ProducteName#&pr1id=#ProductId#&pr1pr=#ProductPrice#&pr1br=#Brand#&pr1ca=&pr1va=#Variant#&pr1qt=#Quantity#&z=#Randomly generated unique id#
Any ideas about what is wrong or how to debug it is welcome

You shouldn't do that on the backend. The correct way is to do that on the frontend
The easiest and the correct way is to send data to your dataLayer and then in GTM send an event to GA.
P.S. In your C# code I can see the problem that you are not awaiting async method. If your method is not async, then you can use it like that:
var temp = httpClient.SendAsync(new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
}).Result;

Related

Accessing the Microsoft Graph after OpenId Connect Azure AD Callback

Fundamentally all I need to do is grab a users profile photo after successful login (asp.net 4.8) since it doesn't seem that I can request the photo to come over with the login claims.
This is the callback handler
SecurityTokenValidatedNotification<Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification
This is how I get the Identity from that callback and it's all there looking good
var identity = notification.AuthenticationTicket.Identity;
So I'm trying to callback with RestSharp
var client = new RestSharp.RestClient("https://graph.microsoft.com");
var request = new RestSharp.RestRequest($"/v1.0/users/{email}/photo/$value", RestSharp.Method.GET);
var callbackResult = client.Execute(request);
Debugger.Break();
if (callbackResult.StatusCode == HttpStatusCode.OK)
{
Debugger.Break();
}
But it keeps (I suppose OBVIOUSLY) coming back as unauthorized. Is there some token or something I can use now that the user has authenticated to add a header or querystring or something that will just get me the extra data easily?

How to correlate two AppInsights resources that communicate through NServiceBus?

Currently, I have dozens of .NET services hosted on various machines that show up as Resources on my AppInsights Application Map, which also shows their dependencies with respect to each other, based on the HTTP requests they make.
However, the relationships between services that communicate through NServiceBus (RabbitMQ) are not shown. Now, I am able to show the messages that are either sent or handled by a service via calls to TelemetryClient.TrackXXX(), but not connect Resources on the map using this information.
I have even gone so far as to attach the parent operation ID from the NSB message sender to the message itself, and assign it to the telemetry object in the receiver, but there is still no line drawn between the services in the Application Map.
To reiterate, this is what I'm getting in the Application Map:
(NSB Message Sender) --> (Message sent/handled)
And this is what I want:
(NSB Sender) --> (Receiver)
The services in question are .NET Core 3.1.
I cannot provide the code, as this is for my work, but any help would be greatly appreciated. I've searched everywhere, and even sources that seemed like they would help, didn't.
(not signed in, posting from work)
Alright, I finally got it. My approach to correlate AppInsights resources using their NSB communication is to mimic HTTP telemetry correlation.
Below is an extension method I wrote for AppInsights' TelemetryClient. I made a subclass named RbmqMessage:NServiceBus.IMessage, given my applications use RBMQ, and gave it the following properties for the sake of correlation (all set in the service that sends the message) :
parentId: equal to DependencyTelemetry.Id
opId: value is the same in the sender's DependencyTelemetry and the receiver's RequestTelemetry. Equal to telemetry.context.operation.id
startTime: DateTime.Now was good enough for my purposes
The code in the service that sends the NSB message:
public static RbmqMessage TrackRbmq(this TelemetryClient client, RbmqMessage message)
{
var msg = message;
// I ran into some issues with Reflection
var classNameIdx = message.ToString().LastIndexOf('.') + 1;
var messageClassName = message.ToString().Substring(classNameIdx);
var telemetry = new DependencyTelemetry
{
Type = "RabbitMQ",
Data = "SEND "+messageClassName,
Name = "SEND "+messageClassName,
Timestamp = DateTime.Now,
Target = "RECEIVE "+messageClassName //matches name in the service receiving this message
};
client.TrackDependency(telemetry);
msg.parentId = telemetry.Id;
msg.opId = telemetry.Context.Operation.Id; //this wont have a value until TrackDependency is called
msg.startTime = telemetry.Timestamp;
return msg;
}
The code where you send the NSB message:
var msg = new MyMessage(); //make your existing messages inherit RbmqMessage
var correlatedMessage = _telemetryClient.TrackRbmq(msg);
MessageSession.Publish(correlatedMessage); //or however the NSB message goes out in your application
The extension method in the NServiceBus message-receiving service:
public static void TrackRbmq(this TelemetryClient client, RbmqMessage message)
{
var classnameIdx = message.ToString().LastIndexOf('.')+1;
var telemetry = new RequestTelemetry
{
Timestamp = DateTime.Now,
Name = "RECEIVE "+message.ToString().Substring(classNameIdx)
};
telemetry.Context.Operation.ParentId = message.parentId;
telemetry.Context.Operation.Id = message.opId;
telemetry.Duration = message.startTime - telemetry.Timestamp;
client.TrackRequest(telemetry);
}
And finally, just track and send the message:
var msg = new MyMessage();
_telemetryClient.TrackRbmq(msg);
MessagePipeline.Send(msg); //or however its sent in your app
I hope this saves someone the trouble I went through.

OData without HTTP in .NET Core

I would like to utilize oData without HTTP.
Scenario: "Load Balancer" oData-capable service receives requests from
clients, puts them into a queue (in serialized form), then "background" workers pick up
messages from the queue and process the request (get data from data
storage and provide response)
And it seems that such functionality either it is not exposed in MS oData libs, or it is so simple and obvious (though not for me) that nobody cares to highlight it in the docs.
I see it something like (pseudo-code)
var model = GetEdmModel();
var processor = GetProcessor(); // something like ODataController in AspNet.oData - contains functions and whatever
var request = GetRequestFromQueueAndParse();
var uriPath = request.Path; // like "/Books"
var queryString = request.QueryString; // like "$filter=price lt 50"
var method = request.Method; // GET or POST or ...
var body = request.Body;
// *** here is what I am looking for ***
var response = SomeMagicODataHelper.ProcessQuery(model, processor, method, uriPath, queryString, body);
ProvideResponseBackToBalancer(response);
Is there something alike provided by (preferable) standard MS oData library, or as a third-party library?

Return a parameter in Google App Script callback

The following example code successfully performs a callback to the Google App Script:
var SCRIPT_ID = "1eC5VsM2vkJXa9slM40MTKTlfARGAGyK1myMCU3AB_-Ox_jGxQaoPM8P2";
function getURL() { return getCallbackURL('testCallback'); }
function getCallbackURL(callback) {
var state = ScriptApp.newStateToken().withTimeout(3600).withMethod(callback).createToken();
return 'https://script.google.com/macros/d/'+SCRIPT_ID+'/usercallback?state='+state;
}
function doGet(e){ return HtmlService.createTemplate(" <div><p><a href='<?=getURL()?>' id='start-auth'><?=getURL()?></a></p></div>").evaluate()); }
function testCallback(e){
Logger.log('myVariable1= ' + e.parameter.myVariable1); // this doesn't work
Logger.log('myVariable2= ' + e.parameter.myVariable2); // this doesn't work
return HtmlService.createHtmlOutput('<b>Success. You can close this window. !</b>')
}
However I need to return a variable to the "testCallback" method as part of a HttpRepsonse redirect. I've tried settings a cookie and also setting a header variable in my asp.net C# application as follow:
HttpCookie cookie = new HttpCookie("myVariable1");
cookie.Value = "someValue1";
cookie.Expires = DateTime.Now.AddMinutes(1);
Response.Cookies.Add(cookie);
Response.AddHeader("myVariable2", "someValue2");
Response.Redirect(applicationCallbackUri, true);
but it's not clear whether the header or cookie variables are available to Google's callback method:
function testCallback(e){
Logger.log('myVariable1= ' + e.parameter.myVariable1);
Logger.log('myVariable2= ' + e.parameter.myVariable2);
return HtmlService.createHtmlOutput('<b>Success. You can close this window.
!</b>')
}
I've also tried using the .WithArguments method when creating the a new state token, but I'm not sure if its possible for my asp.net application to update the state object's arguments as part of the redirect/return.
I've also tried appending the variable to the Google Callback URL, e.g.
https://script.google.com/macros/d/1eC5VsM2vkJXa9slM40MTKTlfARGAGyK1myMCU3AB_-Ox_jGxQaoPM8P2?state=ADEpC8w0dL6mBVmDQHX3XcYcBP0JqQ5_etc&myVariable1=someValue1
However Google throws an "invalid state" error
The event object passed to your testCallback(e) function cannot reference HTTP headers or cookies and appending arbitrary url variables to the redirect url won't work either (the authorization server that does the redirect will omit them to ensure security).
The only valid way to send state vars is using the withArguments() method. However, your Logger.log() calls won't work b/c the calls (to the testCallback(e) function) are asynchronous and they are not tracked in the editor. Instead, try enabling StackDriver Logging from the Apps Script Editor's View menu and replace those Logger.log() calls with console.log(). Your logs should then show up under StackDriver Logging in your Google API Console for the project.

web api (asp.net) - sending data via post method

I'm trying to pass data via post method from my client to a server.
I'm using WebApi to do so.
This i the code i used:
client:
var client = new RestClient();
client.EndPoint = #"http://localhost:57363/hello";
client.Method = HttpVerb.POST;
client.PostData = "{value: Hello}";
var json = client.MakeRequest();
Console.WriteLine(json);
Console.Read();
server:
// POST api/<controller>
public string Post([FromBody]string value)
{
return value + ", world.";
}
The server responds as expected when using postman. However, the client passes a null value instead of the real value.
What am i doing wrong?
First of all a correct json would look like "{value: 'Hello'}".
I use json-online to easily validate such inline json.
On the other hand, I think that you should send just the value in this case, not the entire json (because you are trying to resolve a simple type,a string), so the client should send a request like:
client.PostData = "'Hello'";

Resources