Set Busy status from additional Google calendars

Today I once again faced the fact that a meeting in one calendar was not displayed as a busy time in another calendar; thus, I had 2 invites for the same time in 2 calendars. I also have a personal calendar, which I also use, and it’s not very cool when someone makes an invite for the time when you have to visit the dentist.

I tried to find a normal solution, but I couldn’t find anything, so I made a simple doxy with an app script:

All other calendars must be shared on the main calendar, to which you want to add occupied slots, and you will actually need to execute the script under the user who will add all the calendars to the calendar.

  1. Copy the spreadsheet to your account and rename it, the way you’ll find it later.
  2. In column “A” add all the calendars you need to copy the “Busy” status.
  3. In column “B” add the calendars, where to add the “Busy” slots.
  4. In column “C” we set how many days ahead to review.
  5. Press the button “Test run” – accept the permissions, because this is a simple script, then it will still swear, which is unsafe.
  6. Check the calendar. The events should have “shadows.”
  7. Press the “Create trigger” button – the script will be executed every hour.

What’s under the hood: the script goes through the calendars, checks up all events, except those with “Busy from” in the name or declined. It creates an “uninformative” event in the required calendars, just so that it is reflected that the user is busy at this time. Accordingly, if the calendar is shared, then a refusal will automatically come, or it will automatically be reflected for the shared calendar.

The trigger checks the future once an hour and creates it for all meetings that do not yet have a corresponding “shadow.”

Measurement protocol V2 Google analytics Apps+Web

In Ringostat, historically, we have integration with Google Analytics from the beginning. That is a requirement.

As call tracking, we need to post data about phone calls to sessions of clients, so they will count as events, decrease bounce, and can be used as goals.

With Google Universal Analytics and release of measurement protocol, this integration became much better, and the first call we registered through measurement protocol on December 29th, 2012, it was in closed beta for that moment. As I know, we were the first call tracking service to do that, but I made a big marketing mistake not to use this in communication.

But time moves forward, and Google Analytics has a new stage in beta Apps+Web, and we got a client that uses that type of account. And we discovered that our integration doesn’t work because of new collect endpoint and entirely different way events work there.

But there is still so low amount of information the only useful article I found from David Vallejo, but it’s not currently cover what mandatory fields are and how to get their values.

So in this article, I’ll share a summary of mine tries and fails. Which fields mandatory and how to fill them.

Same as previously, we need to send data to collect endpoint, but now it has another URL. Also changed the protocol version, now it’s 2. And the way how tracking ID now looks like and now it’s not tracking ID but stream ID, and you can have different streams for one property.

Still, you need client ID to post data to the same client, but to get it now, you need to get ‘vid’ property of ‘gaGlobal’ object. Just call ‘gaGlobal.vid’ in javascript instead ga.getAll()[0].get(‘clientId’) as you could do previously. There is a lot of other differences that I’ll not cover in this article. But the main difference for me is new params:

  1. Session ID, for session ID, used UNIX timestamp of session start and stored in the new cookie that has a name like _ga_XXXXXXXXX where XXXXXXXXX is stream ID without G-.
  2. Session count, number of sessions for this clientId. Weird thing, but it looks like this is required, but it also stored in the cookie.

To parse those variables from the cookie in one line I modified suggested snippets of code to:


Just fix XXXXXXXXX with yours stream ID.

Long story short, we need to build the request with the parameters that I found as required and still send it to I found strange information that I have to use only POST request with separation some parameters in URL and other in payload, but GET works fine also. So the params are

ParametermeaningWhat should we use here
vProtocol Version2
tidStream IDG-XXXXXXXXX (find in account or your code)
cidClient IDjavascript: gaGlobal.vid
sidSession IDjavascript: document.cookie.match(‘(^|;)\\s*_ga_XXXXXXXXX\\s*=\\s*([^;]+)’).pop().split(‘.’)[2]
sctSession Countjavascript: document.cookie.match(‘(^|;)\\s*_ga_XXXXXXXXX\\s*=\\s*([^;]+)’).pop().split(‘.’)[3]
dlDocument locationjavascript: document.location
enEvent namestring, how you want to name your event ex. ‘call’

Also, it’s good to add _dbg=1 for debugging to see data in realtime at DebugView (extremely cool feature!).

After collection such params you can build URL that would look like:

Call it, and in 10 seconds, see the event in DebugView if you have done everything right. After that, you can improve this call with additional event params and user params.

Trends for eCommerce according to COVID-19

I tried not to post this, but I feel that I have to.

Panic, according to coronavirus (COVID-19) and the current international economic situation, will lead to changes. I’m not a prominent economist neither virologist.

But something I understand and as I see the possibilities. In the situation with panic levels increase and more attempts used to stop spread the virus are implemented: cancelation of significant events, quarantines, etc. will lead to a new wave of people to adopt eCommerce and delivery services.

Continue reading Trends for eCommerce according to COVID-19