Is there a way to track a user active time spent in the React web application via Google Analytics? - reactjs

Let's say an user with user_id(1000) and email(user101#example.com) logged into the reactjs based web application and browsed a few pages for 2mins and then moved to other application tabs/windows for 30mins and came back to the web application and browsed the app for 5more mins on April 1st 2021.
I would like track/get this user's time spent report in the Google Analytics report saying user101#example.com with user_id(1000) has spent 7mins on April 1st 2021. Is there a way to track the same via GA if possible with react-ga, if it is possible how can we do it?
As of now with react-ga I'm tracking the userid property like the below:
ReactGA.set({userId});
If it is not possible via Google Analytics, is there any service provider that has this kind of feature?
Note: I have gone through existing q/a but unable to find/figure out the solution.

I was able use another tracker Riveted, which by it's definition:
Riveted helps fix this by measuring the amount of time users are
actively engaged (e.g., clicking, scrolling, using the keyboard) and
then reporting the data to Google Analytics in frequent intervals.
More on it's page.
While Riveted is written with a direct global variable, we need to work around to make it available for the react project using exports-loader.
Here is what I could achieve:
Get the riveted.js locally as a file
Ensure to install the exports-loader via npm install exports-loader --save
Import the same with the location of revited.js as:
import riveted from 'exports-loader?exports=riveted!./riveted.js';
After you have initialised ReactGA.initialize(configs);
If you check the source code of riveted, you will notice it's using the same ga object of window.ga and thus the google analytics once initialised via ReactGA.initialize should be enough.
The react-ga provides an ability to extend ga. They state ga can be accessed via ReactGA.ga() method. This gives developers the flexibility of directly using ga.js features that have not yet been implemented in ReactGA. No validations will be done by ReactGA as it is being bypassed if this approach is used.
Then the ga allows writing a custom plugin
So with all that here is what the code looks like:
import React, { PureComponent } from 'react';
import ReactGA from '../../src';
import riveted from 'exports-loader?exports=riveted!./riveted.js';
export default class App extends PureComponent {
constructor(props, context) {
super(props, context);
this.state = {
reactGaInitialised: false,
configs: [DEFAULT_CONFIG]
};
}
initReactGA = (event) => {
const { configs } = this.state;
ReactGA.initialize(configs);
// Send initial test view
ReactGA.pageview('test-init-pageview');
function TrackerCustomPlugin() {
this.riveted = riveted;
}
TrackerCustomPlugin.prototype.init = riveted.init;
let ga = ReactGA.ga();
ga('provide', 'riveted', TrackerCustomPlugin);
ga('require', 'riveted');
ReactGA.plugin.execute('riveted', 'init', {
reportInterval: 10, // Default: 5
idleTimeout: 20, // Default: 30
nonInteraction: true // Default: true
});
};
Here is how the events are sent to GA from my local:
And the GA Dashboard showing Time Spent:

Related

What is the web-vitals, comming with create-react-app?

I have just recognised that my newly created Reactjs application have a file src/reportWebVitals.js, which is being called in index.js. What is this file/pice of code for?
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
It is a third-party library is used to capture and measure user experience metrics comming as a default with create-react-app.
The web-vitals library is a tiny (~1K), modular library for measuring all the Web Vitals metrics on real users, in a way that accurately matches how they're measured by Chrome and reported to other Google tools (e.g. Chrome User Experience Report, Page Speed Insights, Search Console's Speed Report).
They are grouped under two title;
Core Web Vitals
Cumulative Layout Shift (CLS)
First Input Delay (FID)
Largest Contentful Paint (LCP)
Other Web Vitals
First Contentful Paint (FCP)
Time to First Byte (TTFB)
for more detail -> https://github.com/GoogleChrome/web-vitals

Sentry for micro frontends

Is there any possibility to initialise Sentry twice on a page? Use case would be error tracking for parts of the app that are inserted as microfrontend.
So errors happen in this part of the app should be send to the teams own sentry project. I also wonder if there is any way filter the errors so only the ones that are relevant for the microfrontend are send and others are filtered out. Could we use reacts error boundaries for that?
Looks like there is a way to initialize something called Hub with a second dsn like this:
import {BrowserClient, Hub} from '#sentry/browser';
const client = new BrowserClient({
dsn: 'micorFrontEndSntryInstance'
});
const hub = new Hub(client)
this hub can passed to an ErrorBoundary wrapping your component.
In every componentDidCatch we can then send the error to the micro frontends sentry:
componentDidCatch(error, errorInfo) {
this.props.hub.run(currentHub => {
currentHub.withScope((scope) => {
scope.setExtras(errorInfo);
currentHub.captureException(error);
});
})
}
All the code is from this example implementation.

Cesium using local/offline tileserver (TypeScript)

I am trying to set up a local/offline tileserver to serve Cesium's tiles for the 3D Planet/Globe. I have completed my setup for Resium and Cesium based on the following thread I created. After the necessary setup I then retrieved a Precompiled Cesium Assets provided by cesium and placed it within my Python Server. I Have also came across the following guide for Offline Cesium as well as an example for Online Cesium.
After following the guide I noticed that it wasn't working as expected and found out that createTileMapServiceImageryProvider has been deprecated, so I decided to use UrlTemplateImageryProvider instead.
Next, I began to render react cesium using the following code.
First, I did the necessary Imports
import * as cesium from 'cesium';
import * as React from 'react';
import { Entity, PointGraphics, Viewer } from 'resium';
Secondly, I created my Tile Server Properties
const tms = new cesium.UrlTemplateImageryProvider({
url: 'https://localhost:5000/{z}/{x}/{y}.png',
maximumLevel:10,
})
Once created I used it for my Viewer.
<Viewer
baseLayerPicker={ false }
geocoder={ false }
imageryProvider={ tms }
full={ false }
homeButton={ false }
fullscreenButton={ false }
vrButton={ false }
infoBox={ false }
navigationHelpButton={ false }
>
<Entity position= { cesium.Cartesian3.fromDegree(-74, 40, 100) }>
<PointGraphics pixelSize={ 10 }/>
</Entity>
</Viewer>
Even with the following settings above I noticed that my "Network" tab is not retrieving the necessary PNG Files. Which means that cesium is not even attempting to render my Planet/Globe for some reason.
Currently, there are two errors within my console which states importScripts failed for Workers/createVerticesFromHeightmap..... and TypeError: data.loaderConfig is undefined
It can be noted that geocoder and baseLayerPicker is set as false to prevent an error related to cesium ion default access token.

How to use the new #Shopify/app-bridge with #Shopify/polaris-react

Shopify recently released their new #shopify/app-bridge, but it is unclear to me how it should be used alongside #shopify/polaris.
For example, I have tried to make a React component that will use the app-bridge and polaris to display a toast.
import React, { Component } from "react";
import * as PropTypes from "prop-types";
import { Toast } from "#shopify/app-bridge/actions";
import { Page } from "#shopify/polaris";
class Start extends Component {
static contextTypes = {
polaris: PropTypes.object
};
showToast() {
console.log("SHOW TOAST");
console.log(this.context.polaris.appBridge);
const toastNotice = Toast.create(this.context.polaris.appBridge, {
message: "Test Toast",
duration: 5000
});
toastNotice.dispatch(Toast.Action.SHOW);
}
render() {
this.showToast();
return (
<Page title="Do you see toast?">
<p>I do not see toast.</p>
</Page>
);
}
}
export default Start;
But it does not seem to dispatch the action. Any ideas on why not? Note that my app is wrapped in the AppProvider and app-bridge is initialized.
ReactDOM.render(
<AppProvider
apiKey={process.env.REACT_APP_SHOPIFY_API_KEY}
shopOrigin={queryString.parse(window.location.search).shop}
>
<Start />
</AppProvider>,
document.getElementById("root")
);
Any suggestions?
So after a lot of debugging, I found out from Shopify that inside App Bridge, before taking any action, they check that the localOrigin matches the appURL (one that's entered in the partners dashboard). In my case, I have a backend (node.js on heroku used for authentication) and a frontend (react bundle on firebase) my app starts by hitting the backend, and then if authentication checks out, it redirects to the front end. And hence the localOrigin does not match... hmmm, I'm very glad to have figured this out since I lost a lot of sleep over it. Now the question is what to do about it... maybe this is something that could be updated with AppBridge? Or is there a better design I should be considering?
There is now #shopify/app-bridge-react,
https://www.npmjs.com/package/#shopify/app-bridge-react
Shopify supposedly doesn't have docs for it yet though... But, someone can update my answer when they come out with them. :)
NOTE:
Be sure to have, static contextType = Context; to get access to this.context for dispatching actions/etc in your components.
(Hopefully this saves you days of suffering haha I'm not a React developer, so, yeah... this was not marked as "crucial" or anything in the examples).
I also wanted to address #SomethingOn's comment, but I don't have enough reputation to comment...
You actually can debug an iframe. In chrome dev tools, on top where it says "top", you can actually select a frame that you want to debug.
https://stackoverflow.com/a/8581276/10076085
Once you select the Shopify App iframe, type in "window.location" or whatever you want!
Shopify's docs and examples are limited and I'm running into a bunch of issues myself working on a Shopify App, so I just want to spread help as much as possible!

using the googleapis library in dart to update a calendar and display it on a webpage

I am new to dart and I have been trying to figure out how to use the googleapis library to update a calendars events, then display the calendar/events on a webpage.
So far I have this code that I was hoping would just change the #text id's text to a list of events from the selected calendars ID:
import 'dart:html';
import 'package:googleapis/calendar/v3.dart';
import 'package:googleapis_auth/auth_io.dart';
final _credentials = new ServiceAccountCredentials.fromJson(r'''
{
"private_key_id": "myprivatekeyid",
"private_key": "myprivatekey",
"client_email": "myclientemail",
"client_id": "myclientid",
"type": "service_account"
}
''');
const _SCOPES = const [CalendarApi.CalendarScope];
void main() {
clientViaServiceAccount(_credentials, _SCOPES).then((http_client) {
var calendar = new CalendarApi(http_client);
String adminPanelCalendarId = 'mycalendarID';
var event = calendar.events;
var events = event.list(adminPanelCalendarId);
events.then((showEvents) {
querySelector("#text2").text = showEvents.toString();
});
});
}
But nothing displays on the webpage. I think I am misunderstanding how to use client-side and server-side code in dart... Do I break up the file into multiple files? How would I go about updating a calendar and displaying it on a web page with dart?
I'm familiar with the browser package, but this is the first time I have written anything with server-side libraries(googleapis uses dart:io so I assume it's server-side? I cannot run the code in dartium).
If anybody could point me in the right direction, or provide an example as to how this could be accomplished, I would really appreciate it!
What you might be looking for is the hybrid flow. This produces two items
access credentials (for client side API access)
authorization code (for server side API access using the user credentials)
From the documentation:
Use case: A web application might want to get consent for accessing data on behalf of a user. The client part is a dynamic webapp which wants to open a popup which asks the user for consent. The webapp might want to use the credentials to make API calls, but the server may want to have offline access to user data as well.
The page Google+ Sign-In for server-side apps describes how this flow works.
Using the following code you can display the events of a calendar associated with the logged account. In this example i used createImplicitBrowserFlow ( see the documentation at https://pub.dartlang.org/packages/googleapis_auth ) with id and key from Google Cloud Console Project.
import 'dart:html';
import 'package:googleapis/calendar/v3.dart';
import 'package:googleapis_auth/auth_browser.dart' as auth;
var id = new auth.ClientId("<yourID>", "<yourKey>");
var scopes = [CalendarApi.CalendarScope];
void main() {
auth.createImplicitBrowserFlow(id, scopes).then((auth.BrowserOAuth2Flow flow) {
flow.clientViaUserConsent().then((auth.AuthClient client) {
var calendar = new CalendarApi(client);
String adminPanelCalendarId = 'primary';
var event = calendar.events;
var events = event.list(adminPanelCalendarId);
events.then((showEvents) {
showEvents.items.forEach((Event ev) { print(ev.summary); });
querySelector("#text2").text = showEvents.toString();
});
client.close();
flow.close();
});
});
}

Resources