Lesser-known JavaScript APIs
smashingmagazine.com
smashingmagazine.com
Edit: If you want to protect yourself from such abuse, try an extension that spoofs the API.
You can try: "Always active window" on Firefox or "Don't make me watch" on Chrome.
Test it with this website (not mine): https://testdrive-archive.azurewebsites.net/Performance/Page...
These web sites are getting way too abusive with the powerful APIs we've given them. It's time to reassert control.
The browser should be our user agent by default. Not some advertisement displaying, user snitching, corporate money making machine.
https://drewdevault.com/2020/03/18/Reckless-limitless-scope....
Surely it can, we just need to make it happen. It's actual code that helps here, not nihilism.
To quote the wonderful ladybird project[0] (lead by a person who iirc worked on webkit too):
> Q: Why bother? You can’t make a new browser engine without billions of dollars and hundreds of staff.
> Sure you can. Don’t listen to armchair defeatists who never worked on a browser.
[0]: https://awesomekling.github.io/Ladybird-a-new-cross-platform...
why is this frightening? proctoring software has long been used and is much more invasive than this, and the alternative is to simply not allow students to use their own devices, or even to take tests remotely - when i was in school the alternative to this sort of software was an exam proctor sitting behind you and watching your every move to make sure you didn't cheat. i get that outside of this sort of context it's bad, but that doesn't make it bad in the contexts where it actually is appropriate.
On your second point about the comparison of human proctor and this:
Lots of things are fine to do on a small scale, but becomes terribly invasive when you do it on a massive scale with the aid of computers. You may accept that the person driving behind you may take a note of your license plate, but would you say the same if someone installed a high resolution webcam on the pedestrian footbridge to see every single car that went through forever? The general issue with computer-assisted surveillance is that it is cheaply scalable and nearly impossible to erase.
Lastly, is there really a point in preventing the use of external information aids (textbooks, notes, Google) in an age where information is so widely available? Rote memorization has never been a good way to truly learn things, and maybe we should do away with this tradition of tests based on information reproduction.
On top of that, cheating is still possible with readily available tools, even today! (For example, that one AI that shall not be named ;)
>they nevertheless log a bunch of stuff that get sent to the instructor
..what sort of stuff? And how is it related to the visibility api?
It's in the second sentence.
The ability for a website to see when you click on things outside of the page itself (either by changing active window or tab) is quite unexpected from an end-user perspective
> what sort of stuff? And how is it related to the visibility api?It's in the linked article. At least a few of those events are implemented with the visibility api.
I've always chalked this up to "of course you need to be vigilant that I'm not cheating", but with the twist that I hold you to a high ethical bar with the data you collect about me.
Am I wrong to think about it this way?
The intention behind the Page Visibility API is supposed to be to allow the page to stop bothering to run JS intended solely to calculate DOM updates, if said DOM isn't currently being rendered where the user can see it. Like how "damage region"-based redraw event-pumping worked in native apps before window managers started doing compositing; or how culling works in 3D rendering. The browser asks the OS to notify it whenever the tab's viewport is entirely occluded; and when the browser receives said notification, it translates that to a Page Visibility API event for the tab.
And the annoying thing about that, is that an opt-in in this case would do away with all the subtle improvements to battery life that are the "correct" use-case of this API. It'd be like having to explicitly prompt the user to opt-in to allowing the use of WEBMs for displaying animations on pages, while allowing actual .GIF-file animations all the time. Websites that are just websites, not long-use apps, would know that users don't care enough to take the time to understand what's being asked and opt in to using extra APIs with them, so 80% of the time they'd get refused; so, for a "clean experience", they just wouldn't bother to ask, and would instead just consider the API verboten, and stick with doing the worse, more-CPU-intensive thing.
Meanwhile, the malicious use-cases would just ask; because for the malicious use-case, even just those 20% of users who naively default to "yes" to prompts instead of "no" would be enough to ensure they siphon off enough data to sell for sweet, sweet ad-tech dollars. (At least, that's how things seem to be for the similar Background Notification API.)
Effectively, you'd punish honest use-cases of the API (because the devs were only doing it out of the goodness of their hearts, and so a little thing like "80% of users won't benefit" is enough to make those devs not bother), while not really thwarting malicious use-cases (because they're highly incentivized.)
As a side note, can you give a website where this is done? I feel like most modern websites are so bloated that no amount of these subtle optimizations would be better than just having a more minimalistic design, such as not fetching things continuously by default and doing away with unneeded animations.
The browser does already do this. Browsers are already smart enough to not "reflect" DOM updates to currently-hidden parts of the DOM into re-rendering passes. (Which is one reason a lot of people think "virtual DOM" frameworks are silly.)
What the Page Visibility API allows you to save the expense of, is running the JavaScript logic that translate into those DOM update calls. (Think: the logic that decides what horrible banner ad to fetch next, actually pre-fetches it, and then updates the DOM to tell the browser it's the ad that should be being displayed. Disabling that logic when the banner ad isn't visible => no more background network fetches for new ads.)
This requires an API, because the browser can't just be reaching into a Turing machine (i.e. some arbitrary Javascript program that could really be trying to do anything, given that webapps exist) and randomly shutting parts of it off. The browser needs a clear signal to hand that page-embedded Turing machine to say "if you have a part that's just for the sake of figuring out what to show next on the screen, then please stop running that part for now." That signal is a Page Visibility event.
(Though, this isn't the only way to accomplish that. If said Javascript program has provided a clear rendering API to the browser, that works too! I.e., if the page is pumping its logic using Window.requestAnimationFrame, then IIRC the browser can take as long as it likes to call the requestAnimationFrame callback back — and if the window is occluded, that would be a perfect time for the browser to wait on that. But if you think about it, "requestAnimationFrame taking longer to get called back" exposes basically the same data-leak that the Page Visibility API does, so...)
> As a side note, can you give a website where this is done?
YouTube, I believe, has independent video and audio streams, precisely so that whenever you leave the viewport occluded for a few seconds, it can stop bothering to fetch the video stream (or can drop the video stream down to the lowest resolution+bitrate version), while continuing to play the previous highest-negotiated-bitrate audio stream.
> its use in various "ed tech" websites to detect alleged cheating[1] is frightening, to say the least
Because? Monitoring what happens during an exam seems normal and reasonable. There is a limit to what is "reasonable" – monitoring webcam and microphone is not IMHO, but seeing if another tab was opened is fairly reasonable.
Like, if I'm setting up an online exam and my requirement is that I need to know if the window is in focus, I won't let students who don't give that permission participate. And if the browsers don't inform me of the permission state and simply don't send the events, I'd scrap the project and force students to use locally installed proctoring software.
On the other hand, if I'm trying to save resources by suspending live updates and heavy rendering when a user tabs away, asking for a "track your activity" permission would cause a lot of friction and user loss (because even just asking for it sounds creepy). Very few users will notice the resource usage, or if they do, will think it's unavoidable, so I simply won't implement those optimisations.
Everybody loses.
As a side note I think prompts like 'letting website track your identity' is misleading and infantilizing. Just let user know what is being accessed, like
- Do you want this website to know when you left the page? We won't let them know if you don't.
- Do you want to allow this website to save cookies? If you don't, all cookies from this site will be cleared when you close the browser.
At this point, we need to acknowledge that browsing the web safely is essentially an adversarial game against adtech and spyware companies. If we don't fight with all our might, we'll just lose. This isn't 2005 anymore. I too wish we could go back, but we can't.
Those obnoxious cookie pop-ups can go away today. No browser intervention necessary.
You know why? They only exist because the greedy industry really wants to collect and sell your private information at scale. No other reason. So the companies could remove those popups today if they cared.
If you move the dialog to the browser, you will have both the browser dialogs and the non-cookie dialogs (because they will still want to fingerprint you, and collect your data, and sell it)
It’s good that you’re using the API in a noble way, but many will not, so it should be up to the user and the settings of the browser they choose to optimize the use of their computer’s resources.
You optimize your system as best you can without spying on the user, and the rest is up to them.
*##+js(aeld, visibilitychange)
Just add it to `My filters` ~duckduckgo.com,*##+js(aeld, visibilitychange)Even something like asking for camera permission isn't obvious all the time. Tried to build a PWA with camera as the focus, but users weren't always aware of the cam permission. Sometimes it slightly bugged and the cam took a few seconds to load or didn't at all.
It doesn't let pages see what you're clicking on outside of the page. That would indeed be a serious privacy violation. It merely tells the page that it's not on-screen any more. Personally I don't see any problem with that.
> The ability for a website to see when you click on things outside of the page itself (either by changing active window or tab) is quite unexpected from an end-user perspective, and its use in various "ed tech" websites to detect alleged cheating
If the "ed tech" site was detecting what you're doing 24/7, that would be a problem.
But for the 2 - 5 hour period of time that you're taking an exam and have their web page open, is it unreasonable?
At least in our case you’re largely only cheating yourself. Our whole goal is to meet you where you are so you can succeed. We level your options to your ability. By cheating, you’re just going to get presented with harder materials and make it harder for yourself than it already was.
(Edit: since the emoji was prefixed, you could see it on the background tab)
A lot of the specs say that user agents must provide users with a way to disable support for certain API. CSP reporting is one that many uBO users will recognise. But of course, Google doesn't follow that. And many of the aforementioned APIs are not W3C standards and are merely working drafts.
Intl API is great, but I feel it's somewhat hamstrung because Node doesn't have matching APIs.
> document.querySelector('video').playbackRate = 10
or
> document.querySelectorAll('video').forEach(v => v.playbackRate = 10)
I "fixed" it by shutting off auto update on page blur then immediately doing an update on focus.
Are you sure? It seems to be very well supported in Node.js: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
It's a basic tokenizer you can use for NLP pre-processing.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Case in point: Element.insertAdjacentHTML(). Not sure how I missed this pretty basic method, but there it is, helping turn a mess of code I had into a one liner. Itemscope and itemprop attributes as well. Wow, where did those come from? Oh, like 1999? Did I just forget they were there? Maybe. Or maybe I just never noticed.
That doesn't even count the continuous new APIs being added during each Chromium release, which are now pretty much everywhere. Mind boggling.
But yeah, it's ridiculous still conflating the two after all these years of full-stack Javascript developments.
Edit: it's cool and fun, nice weekend project.
This is how I learnt that even desktop operating system (Win10 in this case) nowadays has share feature.
new Number(1234567890).toLocaleString('en-US-u-nu-fullwide', {useGrouping:false});
you can replace "fullwide" with "mathbold", "mathdbl", "mathmono", "mathsanb", "mathsans", etc.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Page Visibility API 98%
Web Share API 90%
Broadcast Channel API 93%
Internationalization API 98%- Page Visiblility is fully supported by all browsers except Opera Mini, and has been for a while
- Same with Intl (aditionally except KaiOS)
- Broadcast is supported by everyone but Opera Mini and Internet Explorer
- Web Share is only fully supported by Safari, Edge, and some Android browsers (Chrome, Samsung, Firefox, Opera Mobile), Chrome only has partial support because only Windows and ChromeOS
That means you can use the first 3 rather reliably, while Web Share is a lot more of a crapshoot.
Imagine an Object where you control _all_ the getting and setting.
Granted in very very tight loop regular object get/set will be faster, but performance is more than good enough today. If you have an use case for it, use it.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Basically youtube sends ads data in a window.ytInitialPlayerResponse variable. My extension loads before and intercepts this variable with proxy to prevent setting of window.ytInitialPlayerResponse.adPlacements field.
When I was writing this code, I looked into ublock origin filters, so this idea or may be even code could have been borrowed there, I don't really remember.
I also override JSON.parse and Response.json functions, because youtube can also send ad data with AJAX. One of those might be unnecessary, I'm not really sure.
declaraoids.findNameAndSexAsGenderWhereAgeGreaterThanXAndAddress_CityEqualsCity(persons, {x: 23, city: 'Bergen'});
[0]: https://github.com/Matsemann/DeclaraoidsIt creates a new data structure that behaves as an object but is backed by SharedArrayBuffer, in order to support parallel computation over it.
Hahahaha no. That's going to be put to use for surveillance and watching when people switch back and forth to the page to maximize ad revenue. I can imagine Twitch using it to determine if the viewer is really looking at the page of if they have gone off to another window, and using that to gauge "engagement" or some other "monetization" metric.
This allows to keep audio while lowering bandwidth, CPU and memory usage.
So yes it may be used for nefarious purposes but it also provides very nice features in a media streaming case.
Also, how long before the video streaming services use the api to adjust streamer compensation rates based on active/not active watchers?
> Also, how long before the video streaming services use the api to adjust streamer compensation rates based on active/not active watchers?
Good remark, that wouldn't surprise me that they don't already do this on such services by the way, though I'm not at all familiar with stream compensation rules.
You made me want to check if they collected it server-side on twitch by curiosity and they do seem to send regularly some engagement-related metrics (others than what I would assume would be useful to monitor if the player is doing a good job, such as bitrate and frame-drop-related matters). For example a base64-encoded JSON with properties such as "minutes_logged" (which I guess are the minutes since I logged in), a "chat_visible" boolean and more interesting here "time_spent_hidden" seems to be POSTed at intervals. That whole object is also conveniently associated to an "event" name called "minute-watched".
What's strange though is that the URL makes it look like they're requesting an usual ".ts" media segment though it is a POST request, it returns an HTTP 204 No Content and more importantly, the request is not performed by their usual media player script but by another mysterious p.js script, which makes it seem that this is not at all actually loading a media segment.
Maybe this camouflage is here to prevent people from messing with it, as wrong data would probably mess with their internal logic, but I guess that it indicates that they do collect that data on their servers, though I don't know what they do with it. Moreover, they already have features to influence users so they stay active on the tab (for example the bonus points you win by clicking regularly on the treasure chest on the bottom of the chat), so that's not that surprising that they monitor this.
1) They default to the user's locale as set in their Browser settings and you don't ever need to look up navigator.language yourself.
The trick to using an options object to something like Intl.DateTimeFormat where the options object is after the locale name is to pass `undefined` as the locale to opt in to the default behavior. (I wish they had swapped the order in constructors to make this easier/more obvious.)
In the article's case can save a line and:
const dateFormatter = new Intl.DateTimeFormat(undefined, { timeZone: 'UTC' })
Also, constructing a formatter like this is for better reuse of the formatter with saved options (ie, moving this up and out of the function defined in the articles instead of building a new one every function call).2) There's one more important way to shrink this article's example down, many built-in JS types including `Date` as all these examples show now include a function directly to format using the appropriate Intl formatter called `toLocaleString`. In this case: Date.prototype.toLocaleString(locale, options) takes all the same options. You can replace the article's formatDate function entirely with toLocaleString:
const parsedQuote = `
<q>${content}</q> <br>
<p>- ${author}</p><br>
<p>Added on ${dateAdded.toLocaleString(undefined, { timeZone: 'UTC' })}</p>`Otherwise left-open tabs appear to be functional until the user does something.
Also, related to Intl replacing tons of code, Moment.js has this disclaimer up top of its README and npmjs.org listing today:
> Moment.js is a legacy project, now in maintenance mode.
But this is not big or bold enough and it is amazing how many projects still rely on a legacy package like this, which is huge because it bundles its own Intl replacement because it predates Intl. (Please use Luxon or date-fns or Intl.DateTimeFormat directly in 2022 rather Moment.js.)
We use Page Visibility API to gauge how focus/interest the prospect is about a particular deal package.
Pretty awesome when combined with converting the DOM to a canvas and then sharing that.
Although later on formatToParts was added which allows the developer to ignore the settings and really only use the bits they wanted anyway.
``` ['B 1', 'A 20', 'A 3'].sort((a, b) => a.localeCompare(b, 'en', { numeric: true })) // ['A 3', 'A 20', 'B 1'] ```
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
[2] https://tc39.es/ecma402/#sup-String.prototype.localeCompare