Is it possible to derive Web Vitals from chrome trace events data? - node.js

I am hoping to get some advice with regards to calculating core web vitals without interacting with PerformanceObserver api but instead to use Chrome trace events.
Since the puppeteer operation is done at scale I prefer to not to interact with the page using page.evaluate but instead calculate the metrics if possible from the data I get using:
await page.tracing.start();
await page.goto(url, { waitUntil: "networkidle0" });
writeFile("dump.json", (await page.tracing.stop()).toString()); -> Can I get web vitals/perf metrics here?
I can see in the output of the trace, events like this:
{
"args": {
"data": {
"candidateIndex": 1,
"isMainFrame": true,
"navigationId": "927C29B0D3BD3783D85D54D161903DEF",
"nodeId": 92,
"size": 145574,
"type": "image"
},
"frame": "8DCDB2C2311B3C524C094C8C4555E0FB"
},
"cat": "loading,rail,devtools.timeline",
"name": "largestContentfulPaint::Candidate",
"ph": "I",
"pid": 94113,
"s": "t",
"tid": 775,
"ts": 437767356341
}
Would be good to know if I am barking up the wrong tree here or I can extract/calculate perf metrics using only the traceEvents data. I am assuming this should be possible since the dump has all the events that took place during page load and the devtools seems to place them metrics on the timeline too.
Many Thanks.

The PerformanceTimeline domain used by the Chrome DevTools protocol may contain the kind of information you're looking for, similar to your screenshot.
The FCP, LCP, and CLS vitals are also recorded in the trace data and accessible via Puppeteer, but there are some caveats to consider:
The correct trace categories should be recorded. Refer to the categories used by DevTools.
The render and frame IDs should be used to disambiguate records between the top-level frame and any iframes. You can get these IDs from the TracingStartedInBrowser event.

Related

Chrome extension content scripts not running on certain sites

I've been attempting to write a very simple Chrome extension (manifest v3) to automatically close those annoying tabs zoom leaves open after you join a meeting.
So far I have been able to get most pages to automatically close with my extension but it simply refuses to run on certain domains, including the one I actually need it to run on: https://company-name-here.zoom.us/. I ultimately would like to set the content script matchers to just zoom but for now I have expanded it to all sites in an effort to reduce sources of error.
It is not working no matter how I attempt to load the page, be it by clicking the redirect url on a google calendar event, reloading the page manually after it has already been opened, and even manually typing out the url and hitting enter. The zoom home page suffers from the same problem but other sites such as stack overflow show the "Content script loaded" console log and close in 5 seconds as I would expect.
Please find the entire source for the extension below:
manifest.json
{
"manifest_version": 3,
"name": "Zoom Auto Closer",
"version": "1.0",
"background": {
"service_worker": "src/background.js"
},
"content_scripts": [{
"run_at": "document_start",
"matches": ["<all_urls>"],
"js": ["src/content.js"]
}]
}
src/content.js
const closeDelay = 5_000;
const closeCurrentTab = () => chrome.runtime.sendMessage('close-tab');
const main = () => {
console.log('Content script loaded');
setTimeout(closeCurrentTab, closeDelay);
};
main();
src/background.js
const closeTab = tabId => chrome.tabs.remove(tabId);
const onMessage = (message, sender) => {
console.log('Received a message:', message);
switch (message) {
case 'close-tab': return closeTab(sender.tab.id);
}
}
const main = () => {
console.log('Service worker registered');
chrome.runtime.onMessage.addListener(onMessage);
}
main();
The issue might be with the usage of <all_urls>.
Google says on the matching patterns docs:
The special pattern <all_urls> matches any URL that starts with a
permitted scheme.
And the permitted schemes are http:, https:, and file:.
I am not too familiar with Zoom, but this article suggests that zoom uses the protocol zoommtg: to launch the the desktop program, so this falls outside of what <all_urls> covers.
Edit:
Now I see that you stated that the urls start with https:// so that might invalidate what I suggested. Still might be worth trying "*://*.zoom.us/*" instead of <all_urls>.
You could try using "*://*.zoom.us/*" instead. If that doesn't work you could try ditching the content script and handling everything in the background service worker.
In the background service worker, you could add a listener for chrome.tabs.onUpdated and check the url value to see if it matches the url for a Zoom tab and close it from there. You would also need to use the Alarms API for the delay.
This method wouldn't be as efficient because it is called on every tab update (not really worth worrying about), but it is a possible workaround if you can't get the content script method to work.

How should I call a Dialogflow CX Messenger script from Google Tag Manager?

I have setup my Dialogflow CX and Messenger on my web site and I want to execute commands with Google Tag manager.
Basically what I want to do is that if a user scrolls more than 75% of a page, vertically, GTM should trigger this example ( taken from https://cloud.google.com/dialogflow/cx/docs/concept/integration/dialogflow-messenger#rendercustomcard )
const dfMessenger = document.querySelector('df-messenger');
const payload = [
{
"type": "info",
"title": "Info item title",
"subtitle": "Info item subtitle",
"image": {
"src": {
"rawUrl": "https://example.com/images/logo.png"
}
},
"actionLink": "https://example.com"
}];
dfMessenger.renderCustomCard(payload);
This code snippet works fine if I embed it in my web page, and also in when GTM triggers and embeds the tag after a scroll the snippet. But when I try the other types of cards, List type is what I would like to use in my case, I the following in my browsers console "DfMessenger: Could not render undefined".
Any clue if this is due to me triggering things from GTM or any ideas what I could test?
Posting this answer from #Per Olsson as a wikianswer:
I figured out what was wrong with const dfMessenger = document.querySelector('df-messenger') dfMessenger.addEventListener('df-request-sent', function (event) { console.log(event) and compared with the objects and found a misspelled wording. Everything works but you have to be really careful with spelling. I still think the documentation is a bit poor though, but that is not for this forum.

Problems playing, pausing & resuming on Google Assistant (Actions on Google) with live streaming Audio/MP3s using Actions Builder?

This is my first post on StackOverflow (long-time lurker, first-time poster), so go easy on me. ^__^;
For those having trouble in implementing play/pause/resume functionality with a STATIC mp3 I’m assuming the process is the same, so hopefully, this post will help you guys as well.
I’m working on building a live mp3 streaming Google Action, and I seem to be having issues with implementing it in the new Actions Console https://console.actions.google.com/
According to the Google Actions documentation found here:
https://developers.google.com/assistant/conversational/prompts-media - Last updated 2021-03-10 UTC.
I should be able to invoke a Media Response to play an mp3 back to the user using the YAML / JSON example provided in the above link, however, it seems that playing, pausing, and resuming doesn’t work correctly with a streaming mp3 URL.
TLDR; Here's a shorter version of the write up:
https://imgur.com/a/FIgOsl8
For a more detailed analysis see below:
STEPS TO REPRODUCE
Starting with the example provided in the documentation and popping the JSON version sample code (posted here for convenience) in the On Enter section of the scene; I was able to play the media fine.
{
"candidates": [
{
"first_simple": {
"variants": [
{
"speech": "This is a media response."
}
]
},
"content": {
"media": {
"optional_media_controls": [
"PAUSED",
"STOPPED"
],
"media_objects": [
{
"name": "Media name",
"description": "Media description",
"url": "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3",
"image": {
"large": {
"url": "https://storage.googleapis.com/automotive-media/album_art.jpg",
"alt": "Jazz in Paris album art"
}
}
}
],
"media_type": "AUDIO"
}
}
}
]
}
Note: In the above JSON I removed the start_offset node because it’s currently not supported by iOS and is probably put in there as an example for testing purposes.
Here’s an example of the static mp3 media response playing for reference:
https://downloaddave.com/reviews/clients/momentum-br/ga-sr/Screenshot_streaming_playing_no_error_with_test_mp3.png
I noticed that pausing and resuming the static mp3 does not work unless you enabled the following System Intents:
MEDIA_STATUS_PAUSED
MEDIA_STATUS_STOPPED
MEDIA_STATUS_FAILED
MEDIA_STATUS_FINISHED
Otherwise, if you click on the “pause” icon on the Media Response Player or invoke the pause earcon (earcon = ear + icon) you will encounter the following errors:
Sorry, [Your Action’s Display Name] isn't responding right now. Please try again soon.
Did not find any handling for intent event 'actions.intent.MEDIA_STATUS_PAUSED' on scene 'playStreamingAudio'
{
"endConversation": {}
}
Under the Error and status handling section of the scene I added the system intents as seen in the following screenshot.
https://downloaddave.com/reviews/clients/momentum-br/ga-sr/playStreamingAudio_Scene_Configuration_000.png
Note that if I just transition the MEDIA_STATUS_PAUSED to “No Transition” it gives me an error message, Event handler for ‘playStreamingAudio’ has an empty function call and/or empty transition.
If it goes to “End Conversation” it ends the test and exits out of the Media Response Card rather than giving me the option to resume (which seems like a bad user/conversational flow and probably won't pass review).
Tapping the “pause” icon, typing, or saying “pause” doesn’t work unless the MEDIA_STATUS_PAUSED transitions to another Scene which I’ve called pauseStreamingAudio.
In the pauseStreamingAudio scene, I added a prompt letting the user know they can say “play” or “cancel” along with suggestions indicating the same.
{
"candidates": [
{
"first_simple": {
"variants": [
{
"speech": "You can say play to resume audio or cancel to quit."
}
]
},
"suggestions": [{
"title": "Play"
}, {
"title": "Cancel"
}]
}
]
}
From the pauseStreamingAudio Scene, I added a custom intent “play” to go back to the previous Scene I’ve called playSreamingAudio.
I’m not sure if I’m doing this right BUT IT WORKS!
Streaming mp3
Now that I got the foundation working I swapped out the static mp3 to the streaming audio. Here is the Sample Code JSON Builder with streaming mp3 link & “start_offset” removed and the streaming mp3 link.
{
"candidates": [
{
"first_simple": {
"variants": [
{
"speech": "This is a media response."
}
]
},
"content": {
"media": {
"optional_media_controls": [
"PAUSED",
"STOPPED"
],
"media_objects": [
{
"name": "Media name",
"description": "Media description",
"url": "https://prod-35-230-37-193.wostreaming.net/momentum-kvmifmaac-ibc2",
"image": {
"large": {
"url": "https://storage.googleapis.com/automotive-media/album_art.jpg",
"alt": "Jazz in Paris album art"
}
}
}
],
"media_type": "AUDIO"
}
}
}
]
}
The Content-Type of the streaming file that I’m testing with doesn't specifically end in a *.mp3 and when I check the content type is reads as audio/aacp.
Codec: ADTS
Type: Audio
Channels: Stereo
Sample Rate: 44100 Hz
Bits per Sample: 32
AAC Extension: SBR+PS
This works as and I'm able to stream audio form the source file. See screenshot below.
https://downloaddave.com/reviews/clients/momentum-br/ga-sr/Smart_Display_Time_Error_Infinit_NaN_Nan_redlined.png
However, there is a display error on the Media Response Player at the time index by the bottom right Infinity:NaN:NaN (highlighted in the red box).
Likely related, I can no longer trigger the Pause System Intent anymore. Instead, I get the following error:
https://downloaddave.com/reviews/clients/momentum-br/ga-sr/Screenshot_streaming_pause_error.png
Notice that the drop-down is open and there is no response for me to use and troubleshoot.
I also tried looking through the Actions on Google documentation to see if there could be something wrong with the audio stream I was providing, the best thing I could find was,
“Audio for playback must be in a correctly formatted MP3 file. MP3 files must be hosted on a web server and be publicly available through an HTTPS URL. Live streaming is only supported for the MP3 format.”
I found some info on mp3 specs on the SSML page here, but I’m not sure if this applies to the Media Response https://developers.google.com/assistant/conversational/ssml#audio - Last updated 2021-05-25 UTC.
Does anyone have any ideas on how I can get this working or even troubleshoot this?
Could some of these circumstances be an issue with the Media Player itself? How would one go about fixing this?
Anyway, I hope this helps somebody out there & thanks very much in advance. Any help is most appreciated.

How to extract postback data from payload to parameters in Dialogflow V2

I'm stuck in trying to figure this out and I hope someone out there can help me out. I am using the Dialogflow console to create a bot that requests a user to report "something" by providing his/her location and describing the incident. The bot is integrated with Facebook Messenger. One of my intents has a follow up intent which also has a follow up intent like:
intent 1
|
intent 2
| intent 3
Intent 1 requests for the user's location, intent 2 retrieves the user's location and asks the user to describe the location. Intent 3 SHOULD have all the data in context as it's fulfilled by the a webhook. All the data SHOULD be posted to my server. The problem is that I have failed to get the location data (maybe lat and long) I notice that the data comes back in the following format after the fired event FACEBOOK_LOCATION:
{
"originalDetectIntentRequest": {
"source": "facebook",
"payload": {
"postback": {
"data": {
"lat": 14.556761479425,
"long": 121.05444780425
},
"payload": "FACEBOOK_LOCATION"
},
"sender": {
"id": "1588949991188331"
}
}
}
My question is how to I carry that payload data into my Dialogflow Intent Parameters so that they are carried in context until my webhook is fired? I hope i've explained it well. Thanks for the help guys.
You can use the output contexts to save the parameters.
{
"fulfillmentText":"This is a text response",
"fulfillmentMessages":[ ],
"source":"example.com",
"payload":{
"google":{ },
"facebook":{ },
"slack":{ }
},
"outputContexts":[
{
"name":"context name",
"lifespanCount":5,
"parameters":{
"param":"param value"
}
}
],
"followupEventInput":{ }
}
Once you save the parameters, in the subsequent requests, you can access the parameters by accessing saved context. The lifespanCount will decide how many subsequent calls this context is valid. So in the above, eg. parameters saved in intent 1 will be available till intent 5 (if you have 2 more follow up intents)
You can follow more details here.
I personally like to use the client library to develop webhooks as they are easy to use, featureful and reduces JSON manipulation errors. If you like to use NodeJs based client, you can follow this link.
To expand on Abhinav's answer (and point out what caught me up on this issue). You need to make sure that the entities you extracted have the lifespan to make it to your webhook fulfillment call.
You can adjust the count by editing the number and saving.
The lifespanCount will decide how many subsequent calls this context is valid. - Abhinav
If your parameters are not showing up in your output context they probably don't have the appropriate lifespan.

Chrome extension that focuses items in elements panel

I am trying to develop a chrome extension that among other things, will be able to focus an element in the elements panel of the chrome devtools.
I have been pulling my hair out trying to get this to work today but have had no luck so far.
I think part of the key to cracking what I need is here
Here are the main differences between the eval() and
chrome.tabs.executeScript() methods:
The eval() method does not use an isolated world for the code being evaluated, so the JavaScript state of the inspected window is
accessible to the code. Use this method when access to the JavaScript
state of the inspected page is required.
The execution context of the code being evaluated includes the Developer Tools console API. For example, the code can use inspect()
and $0.
The evaluated code may return a value that is passed to the extension callback. The returned value has to be a valid JSON object
(it may contain only primitive JavaScript types and acyclic references
to other JSON objects). Please observe extra care while processing the
data received from the inspected page — the execution context is
essentially controlled by the inspected page; a malicious page may
affect the data being returned to the extension.
But I cannot find the correct place to send the message to or execute the command in order for this to work I am just repeatedly told the following:
Error in event handler for 'undefined': $ is not defined
ReferenceError: $ is not defined
at Object.ftDev.processMsg (chrome-extension://ffhninlgmdgkjlibihgejadgekgchcmd/ftDev.js:39:31)
at chrome-extension://ffhninlgmdgkjlibihgejadgekgchcmd/ftDev.js:16:7
at chrome.Event.dispatchToListener (event_bindings:387:21)
at chrome.Event.dispatch_ (event_bindings:373:27)
at chrome.Event.dispatch (event_bindings:393:17)
at miscellaneous_bindings:166:35
at chrome.Event.dispatchToListener (event_bindings:387:21)
at chrome.Event.dispatch_ (event_bindings:373:27)
at chrome.Event.dispatch (event_bindings:393:17)
at Object.chromeHidden.Port.dispatchOnMessage (miscellaneous_bindings:254:22) event_bindings:377
chrome.Event.dispatch_
Ideally I would like to use the inspect() method of the chrome console not the $() method.
manifest.json
{
"name": "XXXXX Ad and Spotlight Debugger",
"version": "0.1",
"manifest_version": 2,
"description": "A tool to help you identify and debug XXXXXX ads and spotlights in Chrome",
"devtools_page": "ftDev.html",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html",
"default_title": "XXXXXX Debug Tool"
},
"background": {
"persistent": false,
"page": "background.html",
"js": ["background.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["getFTContent.js"],
"all_frames": true
}],
"permissions": ["tabs","cookies","<all_urls>","devtools"]
}
Then there is similar code in the popup.js, background.js and devtools.js file that essentially boils down to this:
processMsg: function(request, sender, sendResponse) {
switch(request.type) {
case "inspect":
$(request.msg);
sendResponse(request.msg + "successfully inspected");
break;
default:
break;
}
} /*other cases removed for sake of brevity*/
Which when executed results in the error above. I am sure that I am trying to execute the command in the wrong context but I can't figure out how to apply it. In the popup.js file I have also tried executing the $ method as below
chrome.tabs.executeScript(tabId, {code: 'function(){$("#htmlID");}'}, function(){});
Any ideas help would be amazing I can supply more of my code if you think it's necessary but I think this pretty much sums up the problem.
Ok - so I had a look around at the font changer thing and it still wasn't quite what I was looking for in the end but then I had a Eureka moment when I was looking over this page for about the 15th time and realised that I had somehow missed the most important part on the page (at least in order to do what I wanted) which was this method
chrome.devtools.inspectedWindow.eval("string to evaluate", callBack)
It is noted that isn't necessarily a good idea for security reasons as it it doesn't run the code in the isolated world.
Anyway - if I run this code from my devtools' page js-code with the following
chrome.devtools.inspectedWindow.eval("inspect(*id_of_the_div_i_want_inspect*)")
Then it will select this item in the elements page of the devtools... it also made me extremely happy!
:D
I don't know if anyone else will ever need/want this but it too me a long(ish) time to figure it out so I hope it helps other people in future.
You can easily highlight DOM elements in any tab, where your content script is injected. As an example, look at Font Selector extension.
As the source code is available (and thoroughly explained) I'll not post it here. The effect you'll see is that after clicking the browser action button every DOM element under mouse cursor becomes highlighed with red border.
If you want to send some info about selected/highlighted element from the tab into your background page, you can do it via messaging (you have already used it, as I see).

Resources