This is an old revision of the document!
Table of Contents
Brave PageGraph
PageGraph is a page-execution recorder, not a browser automation library and not a graph-neural-network classifier. It patches Brave's Blink and V8 engines so that the browser records a directed, attributed graph of what happened while a page ran: which parser, script, DOM element, frame, resource, or Web API action caused the next event. The practical entry point is pagegraph-crawl, and the output is normally queried after the crawl with pagegraph-query. PageGraph extends the graph representation introduced by AdGraph [1Iqbal, Umar; Snyder, Peter; Zhu, Shitong; Livshits, Benjamin; Qian, Zhiyun; Shafiq, Zubair (2020): "AdGraph: A Graph-Based Approach to Ad and Tracker Blocking", in: 2020 IEEE Symposium on Security and Privacy (SP), pp. 763-776. (DOI)], improving event attribution and capturing more page behaviours [2Siby, Sandra; Iqbal, Umar; Englehardt, Steven; Shafiq, Zubair; Troncoso, Carmela (2022): "WebGraph: Capturing Advertising and Tracking Information Flows for Robust Blocking", in: 31st USENIX Security Symposium (USENIX Security 22), pp. 2875-2892. USENIX Association, Boston, MA. (Link)], and it is the branch of that line that is still maintained; Javascript is the place for the classification questions that sit on top of this trace.
Use PageGraph when attribution is part of the measurement: “which code unit caused this request, DOM change, or API access?” A request log is cheaper when the question is only “which URLs occurred”; taint tracking is the better fit for “where did this value flow?”. PageGraph sits between them: it records causal actors and actions, but it is not a general data-flow tracker.
What the graph contains
The unit to keep in mind is an actor–action–actee triple. A script is an actor; a DOM insertion, storage access, or request is an action; the inserted element, storage/API node, or network resource is the actee. The exact node and action vocabulary depends on the Brave build and the APIs enabled in it, so record that configuration with the graph.
| Graph part | Examples | Why it matters |
|---|---|---|
| Actor nodes | HTML parser; inline, remote, attribute and dynamically compiled JavaScript units; frames and other execution contexts | identifies the party that can be assigned responsibility |
| Actee nodes | DOM elements; child frames; fetched resources; selected Web API and storage accesses | identifies what was changed, fetched, or accessed |
| Action edges | create/insert/modify/delete; script execution; resource request; Web API call | turns a flat event into a causal relation |
| Structural edges | DOM parent/sibling relations and frame/page structure | explains how a script-created element or script got into the page |
| Metadata | source URL, V8 script ID and source location, event order/timestamps, and build-dependent request/response attributes | makes a graph query auditable and lets a later analysis replay the relevant history |
The original PageGraph description gives the useful concrete cases: a script-to-element edge can mean “this script changed the element”, and an element-to-resource edge can mean “this element's src caused the fetch” [3Sjösten, Alexander; Snyder, Peter; Pastor, Antonio; Papadopoulos, Panagiotis; Livshits, Benjamin (2020): "Filter List Generation for Underserved Regions", in: Proceedings of the ACM Web Conference. (DOI)]. SugarCoat's extension makes the model especially clear for privacy work: it records the scripts on the JavaScript stack at a Web API access, the source location of each, and then traverses insertion and execution edges to find scripts injected downstream [4Smith, Michael; Snyder, Peter; Livshits, Benjamin; Stefan, Deian (2021): "SugarCoat: Programmatically Generating Privacy-Preserving, Web-Compatible Resource Replacements for Content Blocking", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security. (DOI)]. The event-loop-turn work uses the ordering metadata to extract a subgraph for one script's deterministic activity, rather than treating the whole page as one undifferentiated trace [5Chen, Quan; Snyder, Peter; Livshits, Ben; Kapravelos, Alexandros (2021): "Detecting Filter List Evasion with Event-Loop-Turn Granularity JavaScript Signatures", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)].
In a simple dependency chain, the graph can retain something like:
HTML parser -> script A -> inserted script element -> script B script B -> inserted image element -> image request to C
That is the distinction from a table of requests. The table tells you that C was requested; the graph lets you ask which element, script and upstream insertion led to it, and whether the request arose in a child frame. PageGraph's current documentation lists script execution, most resource requests, DOM changes, Shields/filter-rule effects, timestamps, remote frames, and GraphML export as supported features.1)
Why this resists request-level attribution errors
Request-level measurement tends to start at the wrong end of the causal chain. A URL, a timestamp, a response, or even a referrer does not reliably say which code unit caused the browser to make the request: referrer policy can change the referrer, and the request may have been made by a DOM element that a different script inserted. The WebREC paper demonstrates the practical consequence: understanding third-party requests requires on-page activities, because a basic request record otherwise has to infer initiators with heuristics [6Hantke, Florian; Snyder, Peter; Haddadi, Hamed; Stock, Ben (2025): "Web Execution Bundles: Reproducible, Accurate, and Archivable Web Measurements", in: Proceedings of the USENIX Security Symposium. (Link)].
PageGraph moves the observation point into the renderer. It connects:
- the parser or script that created an element;
- the element or script that triggered a resource request;
- the script stack and source location at a Web API access; and
- the upstream chain that brought a script, frame, or resource into the page.
This is why the 2020 PageGraph paper reports better attribution than its AdGraph predecessor for cases such as JavaScript in an element attribute (onerror=…) and timer callbacks that reset the ordinary JavaScript stack [3Sjösten, Alexander; Snyder, Peter; Pastor, Antonio; Papadopoulos, Panagiotis; Livshits, Benjamin (2020): "Filter List Generation for Underserved Regions", in: Proceedings of the ACM Web Conference. (DOI)]. It also broadens the observed event set to include, among other examples, image requests initiated by CSS or prefetch, modifications in local subdocuments, and failed requests [3Sjösten, Alexander; Snyder, Peter; Pastor, Antonio; Papadopoulos, Panagiotis; Livshits, Benjamin (2020): "Filter List Generation for Underserved Regions", in: Proceedings of the ACM Web Conference. (DOI)]. The 2025 Local Frames crawl describes the current measurement-facing output in the same terms: salient events plus the HTML element or JavaScript unit responsible for each event, one graph per measured website [7Ukani, Alisha; Haddadi, Hamed; Snoeren, Alex C.; Snyder, Peter (2025): "Local Frames: Exploiting Inherited Origins to Bypass Content Blockers", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security, pp. 1349-1363. (DOI)].
The graph does not prove that an actor intended a purpose, nor does it follow arbitrary values through JavaScript variables. A script can be the causal actor for a request without the graph telling you whether the request carried an identifier. For tracking classification, combine the graph with a filter list, a label source, or manual review, and state which of those supplied the label. For data-flow questions, use a taint-tracking instrument instead.
Current toolchain (checked 2026-08-14)
PageGraph is included in Brave builds from version 1.46 onward, but it is off unless the browser is launched with the right command-line arguments. Brave's wiki does not enumerate them and instead directs you to pagegraph-crawl, which sets them for you — so in practice you only need the flags if you are launching Brave yourself. Recording built-in JavaScript APIs requires a Brave Nightly build, because the stable/beta builds omit that instrumentation for performance reasons; which Web APIs are instrumented is fixed at build time by a interface.py file, and adding more means rebuilding Brave.2) Do not silently substitute “Brave” for “PageGraph”: report the exact browser channel and build, and which API set was enabled.
The usable pieces are:
| Piece | Use now | State and trap |
|---|---|---|
| pagegraph-crawl | drives a PageGraph-enabled Brave binary and writes GraphML recordings | current command-line crawler; the README tests with Node v23.4.0 and warns that Puppeteer/devtools interaction is not itself tracked |
| pagegraph-query | Python CLI; queries elm, html, requests, scripts, js-calls, subframes, unknown, and validate | current query path; run validation and inspect unknown events before counting |
| pagegraph-rust | older Rust library/CLI | archived on 2026-07-21; its README says to use pagegraph-query instead |
The minimal crawl shape documented by pagegraph-crawl is:
npm install npm run build npm run crawl -- \ -b /path/to/Brave\ Browser\ Nightly \ -u https://example.org \ -t 30 \ -o output/ --logging verbose
Do not copy the –debug debug example that pagegraph-crawl's own README still shows. That flag no longer exists: the current argument parser accepts –logging {none,info,verbose} (default info), and –debug debug exits with run.js: error: unrecognized arguments: –debug debug. Verified against src/run.ts at version 1.2.13 on 2026-08-14. It is a good reminder to run any documented command before putting it in a paper's artifact appendix.
Record the Shields state, and do not assume it. PageGraph runs inside Brave, which ships an ad and tracker blocker, so “what the page did” depends on whether that blocker was on. The trap is that the two obvious ways to run it disagree: pagegraph-crawl defaults to -s down — Shields off, so a default crawl sees an essentially unfiltered web — whereas a Brave you launch yourself has Shields on by default. A prevalence figure means something different under each, and –shields is ignored entirely when –existing-user-data-dir is used. Verified against src/run.ts (defaultShieldsSetting = “down”) on 2026-08-14.
The -t value is the dwell time in seconds and is a measurement decision, not a harmless default: a short visit sees a different execution path from a visit that waits for consent interaction, scroll, login, or delayed work. The crawler repository's warning is important for study design: PageGraph does not track Puppeteer/DevTools automation scripts, and changing the document through that automation while recording can fail.3) If the research question requires scripted interaction, document exactly when it happened, test whether the resulting graph remains valid, and report the interaction itself separately from page-caused events.
Cost and failure modes
PageGraph's price is a patched browser, a larger recording, and a version-maintenance obligation.
- Engineering and browser drift. The first corpus description reported approximately 12K lines of Blink/V8 patches [3Sjösten, Alexander; Snyder, Peter; Pastor, Antonio; Papadopoulos, Panagiotis; Livshits, Benjamin (2020): "Filter List Generation for Underserved Regions", in: Proceedings of the ACM Web Conference. (DOI)]. Those patches are now carried in Brave, which removes the need to maintain a private fork for a basic run, but it does not remove Chromium/Brave version drift. Extending the instrumented API set can still require a rebuild. The graph format itself is under-documented: Brave's wiki says of the type documentation it points to that it “is incomplete and being built up as we go”, and the page it points to belongs to the now-archived
pagegraph-rust.4) Budget time for reading GraphML output rather than a specification. - Storage. In the 2022 storage-policy study, 280,219 PageGraph files occupied 405 GB [8Jueckstock, Jordan; Snyder, Peter; Sarker, Shaown; Kapravelos, Alexandros; Livshits, Benjamin (2022): "Measuring the Privacy vs. Compatibility Trade-off in Preventing Third-Party Stateful Tracking", in: Proceedings of the ACM Web Conference. (DOI)]. A later PageGraph-derived archive, WebREC, reports 10.2 MB per
.webarchive on average, of which 1.5 MB was behavior data and 0.4 MB a screenshot; its proxy-HAR comparison averaged 13.6 MB [6Hantke, Florian; Snyder, Peter; Haddadi, Hamed; Stock, Ben (2025): "Web Execution Bundles: Reproducible, Accurate, and Archivable Web Measurements", in: Proceedings of the USENIX Security Symposium. (Link)]. The latter is an archive bundle, not a raw PageGraph-file benchmark, but it is a useful planning scale. - Crashes and incomplete pages. In the 2020 Alexa-100K experiment, the PageGraph issue category accounted for 4,051 of 14,493 failed visits; 85,470 visits completed successfully [9Sarker, Shaown; Jueckstock, Jordan; Kapravelos, Alexandros (2020): "Hiding in Plain Site: Detecting JavaScript Obfuscation through Concealed Browser API Usage", in: Proceedings of the ACM Internet Measurement Conference. (DOI)]. That is a study-specific failure breakdown, not a current universal failure rate. Brave's documentation explicitly prefers crashing over writing an uncertain graph and gives a 5–10% target for crash rate on real sites; treat that as a design goal, not as a measured guarantee.5) Count attempted, valid, invalid, timed-out, and retried pages separately.
- Runtime and analysis cost — no published benchmark. The graph is built during browser execution, then parsed and indexed. Neither the corpus nor Brave's documentation gives a current per-page slowdown figure, a crash rate measured in 2026, or a graph-size distribution, so pilot a few hundred pages on your own hardware before committing to a population size; do not budget from the numbers below, which are all study-specific. A post-hoc query is cheap compared with a second crawl, but retaining every graph, source file and response can dominate storage. Compress only after validating that the query tool can still read the result, and retain the browser build and query version beside the archive.
The official “Known Limitations” list had nine entries when checked on 2026-08-14, and it is worth reading in full rather than trusting this summary: no WebSocket tracking, no worker tracking, request headers not recorded (response headers are), no CSS style= attribution, some JavaScript URLs unhandled, no attribution of requests caused by CSS rules, no tracking of CSS @import, incomplete HSTS/URL-change handling, and large streamed request bodies not recorded.6) WebREC found and reported a PageGraph limitation around event handlers inside SVG elements, later addressed upstream [6Hantke, Florian; Snyder, Peter; Haddadi, Hamed; Stock, Ben (2025): "Web Execution Bundles: Reproducible, Accurate, and Archivable Web Measurements", in: Proceedings of the USENIX Security Symposium. (Link)]; keep a versioned regression test for any event class your result depends on.
PageGraph versus nearby choices
| Instrument | Best question | What PageGraph adds or omits |
|---|---|---|
| HAR/proxy/request log | Which resources and responses occurred? | lower cost and broad compatibility; initiator and DOM cause usually need inference |
| In-page API hooks (JS shims) | Which calls did page-visible JavaScript make? | easy to deploy, but the page can detect or defeat the hook |
| Patched V8 (VisibleV8) | Which browser-API calls happened, and from which script? | the closest rival instrument: also a patched Chromium and not page-detectable, but it traces API calls without PageGraph's causal DOM/request edges — the two are complementary, and [9Sarker, Shaown; Jueckstock, Jordan; Kapravelos, Alexandros (2020): "Hiding in Plain Site: Detecting JavaScript Obfuscation through Concealed Browser API Usage", in: Proceedings of the ACM Internet Measurement Conference. (DOI)] used both |
| PageGraph | Which actor caused this page action or request, and what was the upstream chain? | browser-level causal graph; no general value-flow semantics; Brave/Chromium only |
| AdGraph/WebGraph | Can graph-derived features classify ad/tracker requests? | historical/modeling line, not a substitute for the current recorder; WebGraph is a classifier built from graph features [2Siby, Sandra; Iqbal, Umar; Englehardt, Steven; Shafiq, Zubair; Troncoso, Carmela (2022): "WebGraph: Capturing Advertising and Tracking Information Flows for Robust Blocking", in: 31st USENIX Security Symposium (USENIX Security 22), pp. 2875-2892. USENIX Association, Boston, MA. (Link)] |
| Taint tracking | Did a particular value reach a sink? | answers a different flow question and costs a browser build |
Use in publications
The extraction finds 8 papers that used or produced PageGraph, out of the 1,120 papers that ran a crawl in the corpus (0.7%). It finds 9 tool tuples because one paper records PageGraph twice; every figure here counts papers. The corpus is the seven venues listed on corpus, not the whole web-measurement literature.
| Year | Corpus papers | Papers using or producing PageGraph | Share of that year's corpus |
|---|---|---|---|
| 2020 | 404 | 2 | 0.5% |
| 2021 | 379 | 2 | 0.5% |
| 2022 | 546 | 1 | 0.2% |
| 2023 | 719 | 0 | 0.0% |
| 2024 | 690 | 0 | 0.0% |
| 2025* | 770 | 3 | 0.4% |
| 2026* | 415 | 0 | 0.0% |
The starred years are provisional: 2025 is thin at the edges and 2026 is incomplete by construction. Do not read the zero in 2026 as evidence that PageGraph stopped being used. The 2025 entries are the useful currency signal in this corpus: three papers use it for a crawl, a breakage/tracker detector, or a reproducible execution archive. The corpus supports “PageGraph is current and still being used”; it does not support a claim that it is the dominant crawler.
| Paper | What PageGraph contributed |
|---|---|
| Sarker et al., IMC 2020, Hiding in Plain Site [9Sarker, Shaown; Jueckstock, Jordan; Kapravelos, Alexandros (2020): "Hiding in Plain Site: Detecting JavaScript Obfuscation through Concealed Browser API Usage", in: Proceedings of the ACM Internet Measurement Conference. (DOI)] | complemented VisibleV8's low-level browser-API traces with PageGraph's high-level script provenance for obfuscation measurement |
| Sjösten et al., TheWebConf 2020, Filter List Generation for Underserved Regions [3Sjösten, Alexander; Snyder, Peter; Pastor, Antonio; Papadopoulos, Panagiotis; Livshits, Benjamin (2020): "Filter List Generation for Underserved Regions", in: Proceedings of the ACM Web Conference. (DOI)] | attributed DOM and request chains so blocking could move upstream without breaking the page |
| Smith et al., CCS 2021, SugarCoat [4Smith, Michael; Snyder, Peter; Livshits, Benjamin; Stefan, Deian (2021): "SugarCoat: Programmatically Generating Privacy-Preserving, Web-Compatible Resource Replacements for Content Blocking", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security. (DOI)] | found dynamically injected scripts and source locations of privacy-relevant API calls for rewriting |
| Chen et al., IEEE S&P 2021, Detecting Filter List Evasion [5Chen, Quan; Snyder, Peter; Livshits, Ben; Kapravelos, Alexandros (2021): "Detecting Filter List Evasion with Event-Loop-Turn Granularity JavaScript Signatures", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)] | extracted ordered, deterministic event-loop-turn signatures from graph subgraphs |
| Jueckstock et al., TheWebConf 2022, Measuring the Privacy vs. Compatibility Trade-off [8Jueckstock, Jordan; Snyder, Peter; Sarker, Shaown; Kapravelos, Alexandros; Livshits, Benjamin (2022): "Measuring the Privacy vs. Compatibility Trade-off in Preventing Third-Party Stateful Tracking", in: Proceedings of the ACM Web Conference. (DOI)] | compared non-structural behavior-edge sets under third-party storage policies |
| Ukani et al., CCS 2025, Local Frames [7Ukani, Alisha; Haddadi, Hamed; Snoeren, Alex C.; Snyder, Peter (2025): "Local Frames: Exploiting Inherited Origins to Bypass Content Blockers", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security, pp. 1349-1363. (DOI)] | used one event graph per site to measure salient rendering and execution events |
| Shuang et al., NDSS 2025, Duumviri [10Shuang, He; Zhao, Lianying; Lie, David (2025): "Duumviri: Detecting Trackers and Mixed Trackers with a Breakage Detector", in: Proceedings of the Network and Distributed System Security Symposium. (Link)] | used PageGraph as one component of rendering-graph features for tracker and breakage detection |
| Hantke et al., USENIX Security 2025, Web Execution Bundles [6Hantke, Florian; Snyder, Peter; Haddadi, Hamed; Stock, Ben (2025): "Web Execution Bundles: Reproducible, Accurate, and Archivable Web Measurements", in: Proceedings of the USENIX Security Symposium. (Link)] | carried PageGraph-style behavior graphs into a replayable .web archive |
The historical ordering matters. AdGraph and WebGraph are useful baselines for graph-derived blocking, but their classifier results are not a current PageGraph installation recipe. For a new measurement, read Sjösten for the attribution problem, Chen for extracting stable behavior units, SugarCoat for script/API graph queries, and Hantke for the current archive and maintenance argument. Then read Jueckstock if your outcome is storage policy or compatibility rather than tracker prevalence.
What to report in a paper
At minimum, report:
- the Brave/Chromium channel, exact version or commit, operating system and architecture, and whether Nightly was required for the API set;
- the PageGraph build/configuration, enabled Web APIs, GraphML/query-tool version, and the validation result for every graph retained;
- the population list and snapshot, visit duration, navigation/consent/authentication actions, headful/headless mode, user-agent and vantage point, cache/storage profile, and retry/timeout policy;
- counts of attempted, completed, invalid/crashed, timed-out and discarded pages, with reasons; never silently drop a PageGraph issue;
- the Brave Shields / filter-list state during the crawl, and whether filter-rule effect edges were counted or excluded — this changes what “the page did” means and is the easiest way to make a prevalence figure incomparable;
- the graph unit you count (script code unit, resource, frame, action, event-loop-turn, or page), and whether a paper can contribute more than one unit;
- the attribution rule and its unknown cases: parser-caused, script-caused, cross-frame, CSS-caused, or unassigned; and
- the filter-list/database/manual source used for labels, its version/date, the validation sample, and the query code or enough GraphML examples to reproduce the classification.
If the result is a prevalence claim, keep the denominator at the same unit as the graph query: “sites with at least one matching script” is not “requests”, “actions”, or “graphs”. If the result is a script-classification claim, say whether PageGraph supplied only provenance or also the label. The graph is an instrumented observation of the executed path, not a census of code that could execute.
Methodology and limitations of these figures
- The audit script is
scripts/report_pagegraph.mjs; its unedited output, every query, every paper key, the fold residue, source-fact checks, and quote checks are on the provenance page. Corpus-wide selection and extraction caveats are on corpus. - The population query folds only the two raw tool names
PageGraphandPageGraph crawlerwith an ordered exact regex. It countsusedandproducedtool tuples, then deduplicates by paper. The unmapped residue is empty in this run and is printed as empty rather than hidden. - The 2025–2026 rows are provisional, and the seven-venue corpus omits EuroS&P, ACSAC, RAID, AsiaCCS, CHI and SOUPS. The table is a finding about this corpus, not an adoption survey.
- Nine PageGraph evidence quotes were checked against
paper.cols.txt: 5 exact, 3 partial after the dataset's five-word-window check, and 1 below threshold. The one below-threshold quote was manually confirmed; a column-repair hyphenation joined “Chromium-based” in the source rendering.
Related pages
- Javascript — classifying the JavaScript that the graph observes.
- Requests — request-level filter lists and their attribution limits.
- Crawler — generic automation and other specialised crawlers.
- OpenWPM — in-page instrumentation through an unbranded Firefox.
- Traffic files — capture and archive formats that PageGraph-derived graphs can complement.
References
- [1]
- Iqbal, Umar; Snyder, Peter; Zhu, Shitong; Livshits, Benjamin; Qian, Zhiyun; Shafiq, Zubair (2020): "AdGraph: A Graph-Based Approach to Ad and Tracker Blocking", in: 2020 IEEE Symposium on Security and Privacy (SP), pp. 763-776. (DOI)
- [2]
- Siby, Sandra; Iqbal, Umar; Englehardt, Steven; Shafiq, Zubair; Troncoso, Carmela (2022): "WebGraph: Capturing Advertising and Tracking Information Flows for Robust Blocking", in: 31st USENIX Security Symposium (USENIX Security 22), pp. 2875-2892. USENIX Association, Boston, MA. (Link)
- [3]
- Sjösten, Alexander; Snyder, Peter; Pastor, Antonio; Papadopoulos, Panagiotis; Livshits, Benjamin (2020): "Filter List Generation for Underserved Regions", in: Proceedings of the ACM Web Conference. (DOI)
- [4]
- Smith, Michael; Snyder, Peter; Livshits, Benjamin; Stefan, Deian (2021): "SugarCoat: Programmatically Generating Privacy-Preserving, Web-Compatible Resource Replacements for Content Blocking", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security. (DOI)
- [5]
- Chen, Quan; Snyder, Peter; Livshits, Ben; Kapravelos, Alexandros (2021): "Detecting Filter List Evasion with Event-Loop-Turn Granularity JavaScript Signatures", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)
- [6]
- Hantke, Florian; Snyder, Peter; Haddadi, Hamed; Stock, Ben (2025): "Web Execution Bundles: Reproducible, Accurate, and Archivable Web Measurements", in: Proceedings of the USENIX Security Symposium. (Link)
- [7]
- Ukani, Alisha; Haddadi, Hamed; Snoeren, Alex C.; Snyder, Peter (2025): "Local Frames: Exploiting Inherited Origins to Bypass Content Blockers", in: Proceedings of the ACM SIGSAC Conference on Computer and Communications Security, pp. 1349-1363. (DOI)
- [8]
- Jueckstock, Jordan; Snyder, Peter; Sarker, Shaown; Kapravelos, Alexandros; Livshits, Benjamin (2022): "Measuring the Privacy vs. Compatibility Trade-off in Preventing Third-Party Stateful Tracking", in: Proceedings of the ACM Web Conference. (DOI)
- [9]
- Sarker, Shaown; Jueckstock, Jordan; Kapravelos, Alexandros (2020): "Hiding in Plain Site: Detecting JavaScript Obfuscation through Concealed Browser API Usage", in: Proceedings of the ACM Internet Measurement Conference. (DOI)
- [10]
- Shuang, He; Zhao, Lianying; Lie, David (2025): "Duumviri: Detecting Trackers and Mixed Trackers with a Breakage Detector", in: Proceedings of the Network and Distributed System Security Symposium. (Link)
pagegraph-rust.