Google Analytics ID stored in cookie is undefined - cookies

We are installing google analytics via Google Tag Manager.
We have custom variable that supposed to take the GA customer id, and send it to our GA.
The variable is defined as follows:
function() {
try {
var cookie = {{GA_ID_Cookie}}.split(".");
return cookie[2] + "." + cookie[3];
} catch(e) {
return 'N/A';
}
}
While {{GA_ID_Cookie}} is a first party cookie variable named "_ga".
In most cases, this values works, but there are some cases where GA_ID_Cookie is undefined (and exception is thrown).
It happens in all browsers. There enough users with "N/A", so its not about cookies disabled issue.
The GTM installs the GA on page view event; It uses this problematic variable as a custom dimension.
My question is how come the ga id is null, and how can we overcome this problem and get the id in other ways.

It is likely that your tag is fired before the cookie is generated.
Try to change the page view to window load. Clear the cookie and retry, it should work.

Like Ashley pointed out you might be facing a race condition whereby you try to access the cookie before it is set by GA.
Please note that the GA cookie ID contains some uninteresting info from the point of view of identifying users, namely the version which should be removed.
If your GA cookie looks like this:
_ga=GA1.2.1033501218.1368477899;
Then the part you're interested in is:
1033501218.1368477899
To retrieve the client ID via the browser, the official way is as follows:
https://developers.google.com/analytics/devguides/collection/analyticsjs/accessing-trackers
// Initializing the `ga` command queue so that commands
// can be queued even if the GA snippet is not loaded
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
// Queuing a command to retrieve the Client ID when the tracker is ready
ga(function(tracker) {
// Logs the client ID for the current user.
console.log(tracker.get('clientId'));
});
If you are using GTM then you need to create a task:
https://www.simoahava.com/analytics/13-useful-custom-dimensions-for-google-analytics/#13-client-id
function() {
return function(model) {
return model.get('clientId');
};
}
If you want to retrieve the Client ID via the server, then you simply need to parse the cookie HTTP header (below example is from request to stackoverflow website) using an HTTP library of your choice and getting rid of the leading GA\d\.\d\. pattern which represents the cookie version.
cookie: prov=f67bae3b-f99c-2f22-84fc-7c2a62862f3d; _ga=GA1.2.1380536973.1571212618; ...

Related

Clearing Cookies Programmatically is not working in Postman and Newman

I need to be able to delete cookies automatically in between requests when they I run my collection of requests in Newman and Postman Runner (mainly Newman).
I followed the suggestion given in this comment by a person from Postman: https://github.com/postmanlabs/postman-app-support/issues/3312#issuecomment-516965288.
But it is not working.
The answer to these two SO questions also tell the same way to go about doing this: Postman: How do you delete cookies in the pre-request script?
Deleting cookies in postman programmatically
Here is the code that I use that the sources above suggest to place in the pre-request script:
const jar = pm.cookies.jar();
jar.clear(pm.request.url, function (error) {
console.log("Error: ");
console.log(error);
//handle error
});
[Note: error is logged as null when I run this code]
I have tried this code many times and also many different modifications of that code. I do white-list the domain too. But I always get the wrong response in the request. When I clear the cookies manually (using the cookie Manager UI dialogue box), the request gives the right response. I need help in determining where the problem could be for me in deleting cookies programmatically.
I also tried this to see what the cookies that I am deleting are:
jar.getAll(pm.request.url, function (error, cookies) {
console.log("Cookies:");
console.log(cookies);
console.log("Error: ");
console.log(error);
});
Here cookies is an empty array. Perhaps that is the problem. But that is very weird since when I check Cookie Manager manually, there are many cookies shown. And once I delete the cookies manually the requests return the right responses.
Another question I had was: What is the purpose of the callback functions that take 'cookies' and 'error' as arguments in the code above. Are these functions called everytime or only under certain conditions? Could not find the purpose of the callback functions in the postman documentation: https://learning.postman.com/docs/postman/sending-api-requests/cookies/
Thank you
If the cookie has "httpOnly" or "secure" header, you can't delete them via script in postman. jar.clear clears all the cookies except these httpOnly and secure ones.
I think this is a bug and needs to be fixed by Postman. If this is intended, there should be a setting in Postman to activate or disable it.

On what domain is my Javascript in my Office Add-In

We have an Outlook Add-In which runs in OWA.
The Manifest sits on https://company.ourdomain.com
The Javascript sits on https://company.ourdomain.com
The Custom Web Service we wrote in-house sits on https://company.ourdomain.com
When I make a call from within JavaScript in response to an Add-In Command, I use the format https://company.ourdomain.com/api/Controller/Action in the ajax call.
I end up getting one of those CORS errors (sometimes it's pre-flight, other times CORB). Why am I getting this if the Javascript is literally sitting on the same domain as the web service?
I'm assuming I'm authenticated since I've logged into my Outlook account.
What gives?
NOTE:
As an experiment I attempted a RESTful call by directly typing in the URL (No OWA involved). This caused the code to Authenticate against Azure AD. Then afterward I logged into OWA in the same browser session and everything worked fine. Do I actually need to authenticate within the Javascript even if the webservice I'm calling is in the same domain?
AJAX CALL WHICH GENERATES ERROR
Remember, it will work just fine after I've made a RESTful call by making a call to my web service directly from the Browser
var apiUri = '/api/People/ShowRecord';
$.ajax({
url: apiUri,
type: 'POST',
data: JSON.stringify(serviceRequest),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).done(function (response) {
if (!response.isError) {
// response to successful call
}
else {
// ...
}
}).fail(function (status) {
// some other response
}).always(function () {
console.log("Completed");
});
OBSERVATION
When I call the api from the Address Bar the code below is run. This code never gets invoked by Javascript
[assembly: OwinStartup(typeof(EEWService.AuthStartup))]
namespace EEWService
{
public partial class AuthStartup
{
public void Configuration(IAppBuilder app)
{ app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Notifications = new WsFederationAuthenticationNotifications
{
RedirectToIdentityProvider = (context) =>
{
context.ProtocolMessage.Whr = "ourdomain.com";
return Task.FromResult(0);
}
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
Wtrealm = ConfigurationManager.AppSettings["ida:Audience"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = new string[] { $"spn:{ConfigurationManager.AppSettings["ida:Audience"]}" }
}
});
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
});
}
}
}
There are a few problems with this I think.
The first one is you are trying to serve your static content off the same server you are serving your code from. This is in general considered a bad-practice, purely because no point in wasting those precious server resources for static content. Ideally you should upload your static content to a CDN - and let the users' browser make a request to some super-cached file server. However - I understand this option might not be available to you as of now. This also isn't the root cause.
The second and the real problem is, (you think you are but) you are not authenticated. Authentication in Outlook web-addins doesn't come by default, it's something you need to handle. When Outlook loads your web add-in into the side panel it makes certain methods available to you which you can use and kind-of create a pseudo-identity (as an example Office.context.mailbox.userProfile.emailAddress ) - but if you want real authentication, you will need to do that yourself.
There are three ways of doing that as far as I can tell.
The first one is through the Exchange Identity Token
Second one is through the Single Sign On feature
The third one - which I think is the most convenient and the simplest in logic to implement is using WebSockets. (SignalR might be what you need).
When the user loads your first page, make sure a JS value like window.Unique_ID available to them. This will come in handy.
Have a button in your UI - which reads "Authenticate"
When the user clicks to this button, you pop them out to a url which will redirect to your authentication URL. (Something like https://company.ourdomain.com/redirToAuth). This would save you the trouble of getting blocked in the side-panel, because you are using window.open with a url that's on your domain. Pass that Unique_ID to redirection which then redirects you to OAuth login URL. That should look like https://login.microsoftonline.com/......&state=Unique_ID
Right after popping the user to sign in window, in your main JS (which is client-side), you open a web-socket to your server, again with that Unique_ID and start listening.
When the user completes authentication, the OAuth flow should post back either an access token, or the code. If you get the access token, you can send it through the sockets to front-end (using the Unique_ID which is in the parameters of post-back) or if you had the code, you finish authenticating the user with a server-to-server call and pass the access token the same way afterwards. So you use that unique Id to track the socket that user connected from and relay access token to only that user.

Access Cookies in Postman Native App Pre-Request Script

Apologies if been asked before. Tried a quick search and couldn't find.
Situation :
The api is using an authentication token as a cookie name "abc-auth" and this is returned when i hit a /login endpoint. It is returned as a set-cookie header in the response which postman the native app happily accepts and sets up as a domain cookie in the ui
I hoped to basically as a pre-request step hit the login endpoint if the cookie doesn't exist but not hit it if we're already authenticated. So we only login once for the 20 requests rather than 20 times
I had hoped to do this accessing the pm.cookies object which I believe is now fully baked in to the native apps ref -> https://www.getpostman.com/docs/v6/postman/scripts/postman_sandbox_api_reference
So was hoping to do something like this
console.log(pm.cookies.toObject())
if (pm.cookies.has("abc-auth")){
console.log("Found Cookie");
} else {
//send the request
}
Expected :
That it runs the first time logs in and then next time finds the cookie and continues
Actual :
It never finds the cookie. Printing out the cookie list finds an empty array. I am seemingly unable to check cookies from the script.
Anyone know what I'm doing wrong?
A lot of the docs refers to interceptor but as the chrome app is being retired and native app was meant to assume that functionality I would really like the answer to be contained within the native app
Thanks!
Would something like this work for you to do the check:
if (_.keys(pm.cookies.toObject())[0] === "abc-auth"){
console.log("Found Cookie")
} else {
//Do something
}
It's using the Postman cookies function but also the Lodash keys function (which is comes with the native app) It's basically assuming that the first key is the one you want - That's probably not right as it might have several keys.

Postman: How do you delete cookies in the pre-request script?

All the postman cookie-management answers I've seen refer to either the browser extension (open chrome, delete cookies viz interceptor etc) or with the app, using the UI to manually manage cookies.
I would like to delete certain cookies in my pre-request code as part of scripting my API tests. (delete them programmatically)
The Sandobx API docs mention pm.cookies so I tried
if (pm.cookies !== null) {
console.log("cookies!");
console.log(pm.cookies);
}
But the pm.cookies array is empty. Yet in the console, the GET call then passes a cookie.
There's also postman.getResponseCookies, which is null (I assume because we're in the pre-request section, not in the test section)
One answer suggested calling the postman-echo service to delete the cookie. I haven't investigated this yet, but it doesn't feel right.
new version now supports that since 2019/08, see more examples here: Delete cookies programmatically · Issue #3312 · postmanlabs/postman-app-support
Prerequisite
Cookie domains to be given programatic access must be whitelisted.
clear all cookies
const jar = pm.cookies.jar();
jar.clear(pm.request.url, function (error) {
// error - <Error>
});
get all cookies
const jar = pm.cookies.jar();
jar.getAll('http://example.com', function (error, cookies) {
// error - <Error>
// cookies - <PostmanCookieList>
// PostmanCookieList: https://www.postmanlabs.com/postman-collection/CookieList.html
});
get specific cookie
const jar = pm.cookies.jar();
jar.get('http://example.com', 'token', function (error, value) {
// error - <Error>
// value - <String>
});
According to the documentation pm API reference the pm.cookie API is only for the Tests tab, not for the Pre-request Script.
The following items are available in TEST SCRIPTS only.
pm.cookies
...
It seems that you will have to stick with this method : Interceptor Blog post
I know this is a very late answer, but for my case where I didn't want to use the cookies to start the execution of the collection, I just needed to uncheck the option "Save cookies after the collection run" and check the option "Run collection without using stored cookies" on the Runner panel.
And then if I want to manage the cookies on my own, I created a first request on the collection and used the Tests tab just to collect the cookies that I wanted and saved them on a variable.
pm.environment.set('cookie', pm.cookies.get('csrftoken'))
pm.environment.set('sessionid', pm.cookies.get('sessionid'))

ember: using cookies with ember-network

Can cookies be used with ember-network requests? Thanks to this answer I know that they can be used with ember-data API requests, but I need to do a network request in an initializer and it doesn't appear the ember-data store can be accessed that early.
Background:
I'm wanting to persist shopping cart data to the backend for these reasons
The ember-cart addon has a smart way of persisting the cart by jsonifying and data model and dumping to localstore when it changes:
window.localStorage.setItem('cart', JSON.stringify(this.payload()));
then upon return visit parsing the json and pushing it into the store in an instance initializer:
...
payload = JSON.parse(payload);
...
cart.pushPayload(payload);
I'd like to do basically the same thing, but instead of getting the JSON from localstorage, get it from the API via the network.
the store ins't available in an initializer, but ember-network is. So hypothetically I think I can do this. The problem I'm running into is that the cookie isn't being passed.
I get around this with ember-data by using this:
xhrFields: {
withCredentials: true
}
in the application adapter, but I can't find any info about whether there's a similar setting for ember-network. I see the request to my API being made in the initializer, but the api doesn't return anything because the browser cookie isn't included.
The fetch API provides a credentials option..
This is also documented at the whatwg-fetch library used by ember-network.
So basically you can do
fetch("/foobar", { credentials:"include" }).then(...)