Thursday, 20 August 2026

AliExpress webpage keeping multipoint Bluetooth headphones active with WebAudio fingerprinting

Recently I ran into a strange problem with my Bluetooth headphones. They support multipoint Bluetooth audio, so they can be connected to my PC and phone at the same time. Normally the PC takes priority playing audio, with my phone being able to play audio when nothing is playing on the PC.

Usually I listen to music on my phone but with notifications or Youtube playing through the PC, this works reliably until I open an AliExpress page in Firefox or Chrome (other browsers untested).

Shortly after loading the AliExpress homepage, audio from my phone would stop playing. Closing the AliExpress tab fixes it immediately. Muting the tab/Firefox/Windows does not help, and there is no visible video, music, or other media playing on the page. 

This seemed suspicious enough to investigate.

Looking for hidden media

My first thought was an autoplaying product video or advertisement, so I checked for the usual suspects:

  • <audio> and <video> elements
  • calls to HTMLMediaElement.play()
  • active Media Session metadata
  • media requests
  • embedded frames containing media

None of these showed anything useful. There were no audio or video elements, no media playback calls, and navigator.mediaSession.playbackState remained none.

A clue was that the problem did not begin immediately. It appeared after the page had been sitting idle for several seconds. I instrumented the page before loading it and watched the Web Audio API instead of only looking for conventional media elements.

The basic idea was to wrap the AudioContext constructor and record whenever a page created an audio-processing context:

const OriginalAudioContext = window.AudioContext;

window.AudioContext = class extends OriginalAudioContext {
    constructor(...args) {
        super(...args);

        console.log("AudioContext created", {
            state: this.state,
            stack: new Error().stack
        });
    }
};

I also wrapped AudioNode.prototype.connect() so I could see whether anything was connected to the context's audio destination.

That finally found it, two hidden audio contexts!

During an idle capture of the AliExpress homepage, the page created two AudioContext objects. Both entered the running state and both connected nodes to AudioContext.destination.

At the same time there were still:

  • zero <audio> or <video> elements
  • zero media play() calls
  • no active Media Session
  • no audible sound

The constructor stack traces pointed to two scripts:

https://assets.aliexpress-media.com/g/AWSC/uab/1.140.0/collina.js

https://assets.aliexpress-media.com/g/AWSC/fireyejs/1.231.67/fireyejs.js

The first context was created by collina.js, while the second came from fireyejs.js. Both sit under an AWSC directory and appear to be part of Alibaba's browser security and anti-abuse tooling.

The scripts are extremely obfuscated, but enough names and operations survive for AI to work out what the audio code is doing.

What the audio code does

Both scripts build a WebAudio graph resembling this:

Sawtooth oscillator

    -> AnalyserNode

    -> ScriptProcessorNode

    -> GainNode set to zero

    -> AudioContext.destination

The oscillator generates a known waveform. The analyser measures the result after it has passed through the browser's audio implementation, and the script reads frequency data from it.

The gain is set to zero, so the user should not hear anything. However, the graph is still connected to the system audio destination. Connecting it to the destination causes the browser to actively process the graph, even though the final volume is zero.

This is very different from an autoplaying video. There is no media element for the browser's normal tab mute control to stop. As far as the page is concerned, it is performing live audio processing.

In my case, that appears to have been enough for Firefox or Windows to keep the Bluetooth audio path active, preventing my multipoint headphones from switching cleanly back to the phone.

Edit - There seems to be a firefox bug ticket open for the issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1863193#c9  

This looks like fingerprinting

The WebAudio test is not the only measurement in these scripts. Inspection of the bundles found code that queries or measures:

  • canvas rendering and toDataURL()
  • WebGL renderer information, extensions, and shader precision
  • audio oscillator and analyser output
  • screen and viewport dimensions
  • device pixel ratio
  • hardware concurrency and device memory
  • installed browser plugins
  • supported audio and video formats
  • WebRTC behaviour
  • browser performance timing
  • mouse, touch, focus, and scroll events
  • device motion and orientation
  • properties commonly associated with browser automation

There is also code for serialising and encrypting results, making requests to Alibaba telemetry services, and sending data with fetch() or sendBeacon().

This is a fairly comprehensive browser and device fingerprint.

Audio fingerprinting works because small differences in browser versions, operating systems, audio libraries, and hardware can produce slightly different results from the same generated signal. It is not necessarily enough to uniquely identify a device by itself, but it becomes much more useful when combined with canvas, WebGL, hardware, timing, and interaction data. 

Edit - tomrittervg, a firefox developer, has done a further dive into what is being fingerprinted with the WebAudio: https://ritter.vg/blog-webaudio_alibaba.html

I cannot see what AliExpress does with the resulting data after it reaches their servers. It may be used as a persistent device identifier, but it could also be one input into a fraud or bot-detection score. 

Why AliExpress would want this

AliExpress has plenty of reasons to distinguish normal shoppers from automated or suspicious clients as well as tracking users browsing habits. The site has to deal with account takeovers, fake accounts, scraping, automated purchasing, payment fraud, review manipulation, and abuse of coupons or new-customer promotions. They also, like most large businesses, make use of large datasets of user behaviour to better market products and services.

Cookies are not especially reliable for this purpose because they can be cleared, copied, or replaced. A fingerprint made from many independent browser measurements is harder to manipulate consistently.

Interaction data can also help determine whether a browser is controlled by a person or automation. From AliExpress's perspective, this could reduce fraud and allow trusted customers through without showing a CAPTCHA every few pages. Not that Aliexpress shies away from their AI generated CAPTCHAs.

Personally I do not want a shopping homepage silently exercising my graphics, audio, WebRTC, hardware, and motion APIs, etc, to track my behaviours, especially if it has such an annoying effect as blocking my music. Perhaps if AliExpress wasn't blocking my music I never would've looked into what the site was doing.

Blocking it with uBlock Origin

I tested blocking the two identified script families. With both requests blocked, the AliExpress homepage continued to render and no AudioContext objects or destination connections appeared during the control capture.

In Firefox, I use the official uBlock Origin extension by Raymond Hill. To block the scripts open the uBlock dashboard, select My filters, and add:

! AliExpress AWSC fingerprinting scripts

||assets.aliexpress-media.com/g/AWSC/uab/*/collina.js$script,domain=aliexpress.com

||assets.aliexpress-media.com/g/AWSC/fireyejs/*/fireyejs.js$script,domain=aliexpress.com

Click Apply changes, close any existing AliExpress tabs, and open the site again. Existing tabs need to be closed because blocking a script does not shut down an audio context that it has already created.

These rules are deliberately narrow. They block only the two observed script families and only when requested by AliExpress. I would not be surprised if this stops working in the future, I'll cross that bridge when it comes to it.

Because these scripts appear to be connected with anti-fraud systems, blocking them may cause extra CAPTCHAs or problems during login or checkout. So far the homepage and ordinary product browsing still work, but I would temporarily disable the rules if AliExpress refuses a legitimate login or payment.

Why I am blocking it

The anti-fraud use case is understandable, but this implementation has real world problems.

It runs on the general shopping homepage before I perform a sensitive action. It collects a broad set of device and behavioural measurements, the implementation is deliberately difficult to inspect, and there is no visible indication that the page has started a live audio-processing graph.

It also produced a very real hardware side effect. A silent fingerprinting test was able to interfere with Bluetooth multipoint switching, while the browser's mute control did nothing!

If a hidden analytics or security feature can take ownership of an audio path strongly enough to change how external hardware behaves, blocking it seems like a reasonable trade-off.

I also cannot prove how long AliExpress stores the fingerprint or whether it is used across other Alibaba properties. The client code proves that extensive fingerprint-like measurements are collected and transmitted, but server-side retention and identity linkage are not visible from the browser. Can you really trust anyone on the internet to have your best interests at heart?

TL;DR

The AliExpress homepage silently creates two running WebAudio graphs from heavily obfuscated Alibaba security scripts. The graphs generate and analyse a waveform as part of a much larger browser fingerprint, then connect through a zero-gain node to the system audio destination preventing the user from hearing anything.

On my setup, this appears to keep the PC's Bluetooth audio path active and prevents multipoint headphones from switching back to a phone. Muting the tab does not fix it because there is no conventional media element to mute.

Blocking collina.js and fireyejs.js with the two uBlock Origin rules above prevented the hidden audio contexts from being created and means I can happily listen to my music without being interrupted while browsing AliExpress.

Edit - There have been some great discussions on Hacker News that are worth checking out: https://news.ycombinator.com/item?id=49372583

Sunday, 14 June 2026

Construction of Telecortex LED panels

This post will be talking about how the Telecortex LED panels are constructed. The aim was to make something cheaply, quickly and for it to be transportable (light). There are two sizes of panel to suit the 2V icosahedron dome design, the design was planned out in CAD and then transformed into the real world with a lot of time and effort by myself and friends.

The LED panels consist mainly of a a material called coreflute, it is basically a plastic cardboard, often used for signage and is just about perfect for our application. The flexibility of the coreflute has caused us some issues (talk about that later) but it is quite a robust material and very cheap.

 

To cut the large rectangular coreflute panels to size we built a temporary table saw out of plywood and a circular saw (I wouldn't advise doing this but necessity is the mother of all inventions). We also built an adjustable angle guide to aid us in cutting the sheets of coreflute consistently, unfortunately I don't have any photos but it was built from two pieces of striaght wood, a few hinges and a large piece of threaded rod to act as the adjusting side.

 

The size of each LED panel meant that we couldn't fit the whole panel in one contiguous coreflute sheet, to solve that we cut each panel as two pieces and then using thin wooden dowels pushed into the corrugations. Hot glue seems to be one of the only things that sticks to coreflute, we used a thin strip of coreflute hot glued along the spine to keep the two halves from separating.

 

The panels were marked out where an LED strip should be placed, the LED strips were cut to length and then carefully stuck down along the marked lines. We cut wires to the right length to go between the LED strips in the centre to carry power and 2 signal wires were done between the start and end of each LED strip to form a zigzag pattern of LED strip.

 

Due to the flexibility of the material we were getting the solder joints breaking over time due to metal fatigue. To mitigate this we have added aluminium extrusions to the front and back of the panels, this stiffens it up significantly and prevents the hand soldered wires from breaking due to metal fatigue.

Each LED panel has a 48V>5V power supply as discussed in one of the prior posts, this is cable tied to the backside of the panel. The photo below is prior to adding on the aluminium extrusions for rigidity.

The first iteration of the control electronics simply had a 4 pin automotive style connector on each panel which had 4 connections, 48V, SPI data, SPI clock and ground. This was good for a quick assembly and cheap but we were getting signal drop outs which would cause large visual glitches.


This was a lot of labour to produce each panel but they look amazing when running together.

In a later post I will talk about how we upgraded the electronics to fix the electrical interference and visual glitches by using a CAT6A network cabling instead of individual wires like the earlier version.

Friday, 17 April 2026

A faster way to batch export STEP files from Fusion 360

Recently, I have been using Autodesk Fusion 360 for some complex assemblies, which often means exporting a lot of individual bodies into STEP files. If you've done this manually before, you likely know the pain of right-clicking, selecting export, waiting, and repeating the process for every single part.

I initially wrote a basic script to automate this by simply hiding all the bodies except one, exporting the main document, and then repeating the process for the next part. It worked, but there was a massive catch, very time the script toggled visibility and exported, Fusion 360 triggered a timeline recompute. Because my design was parameter-heavy with a long history, exporting a bunch of parts took an agonizingly long time while the Fusion interface locked up.

To get around this, I designed the script to completely bypass the timeline history bottleneck.

The Solution

My script takes a completely different approach to exporting. Instead of fighting the timeline on the main document, the script works like this:

  1. It iterates through the design and finds every body that is currently set to visible.
  2. It silently creates a temporary "Direct Design" document, which has no timeline history at all.
  3. It copies the visible bodies into this temporary document while maintaining their exact global assembly positions.
  4. It exports each one as a pristine .step file directly to a folder you select, and does it almost instantly.

Why it's useful

Because it uses temporary direct modeling documents, there are no parametric history recomputes. What used to take a few minutes now takes seconds. The script also preserves the global coordinates of every component, so if you bring the exported STEP files into a slicer or another CAD program later, they will all assemble perfectly in place.

For naming, it automatically names the exported files based on the component and body name (e.g., Bracket:1_Body1.step). This saves you from ending up with a folder full of files mysteriously named "Body1".

Using it is pretty simple. Just hide the parts you don't want, ensure the bodies you do want are visible, and run the script from the Fusion 360 "Scripts and Add-ins" menu.

In Action

First, make sure the bodies you want to export are visible in your browser tree:



Next, pull up the Scripts and Add-ins dialog and run the step_exporter script:



It will prompt you to select a destination folder for all of your STEP files:



A quick progress dialogue pops up while it churns through the visible bodies (since it skips history recomputes, this goes very fast):



And just like that, your folder is fully stocked with cleanly named STEP files, ready to drop into your slicer or hand off!


All the python source code and instructions are available on my github here.