Privacy policy for HLTV Enhancements
HLTV Enhancements by Plennhar
Privacy policy for HLTV Enhancements
- Effective date: 2026-08-16
- Developer: Plennhar
- Privacy and support contact:
plenhar@proton.me
Summary
HLTV Enhancements is a Firefox extension that runs only on
https://www.hltv.org/*.The developer does not collect or receive personal data from the extension.
The extension has no developer-operated server and includes no telemetry,
analytics, advertising, tracking pixel, crash-reporting service, or data
broker integration. It does not sell data.
The extension locally processes the HLTV pages that the user visits. Local
DOM access and calculations that remain inside Firefox are not a transfer to
the developer or another recipient. Some enabled features make HTTPS requests
to HLTV.org or submit an action to HLTV.org. Those transfers go only to HLTV,
which processes them under its own terms and privacy policy.
Data processed only inside Firefox
The extension can read the content and structure of the current HLTV page to
render enabled features. Examples include forum and match rows, thread posts,
user and team links, timestamps, voting state, match state, player metrics,
statistics tables, filters, and comparison data.
For fetched thread previews, Firefox locally identifies the exact
notification-target reply and derives user flags and player or team flairs
from sanitized thread content. That matching creates no additional request;
supported image loads are separately disclosed below.
The following features use only information already present in
the loaded page and make no additional network request:
- sticky match headers;
- past-three-month player form overlays;
- loaded-row column selection, automatic sizing, sorting, selected calculated
columns, trends, and CSV generation; - comparison-page deltas, highlighting, summaries, swapping, filter-link
generation, and CSV generation; - the temporary on-page indicator shown after a successful block.
CSV and JSON exports are generated locally as browser downloads. The
extension does not upload them.
Setting-help screenshots are packaged with the extension and loaded through
an exact local allowlist. Opening screenshot help does not contact a website.
Communication handling
The Report a bug or submit feedback link in the in-page settings uses the
fixed destination
mailto:plenhar@proton.me. Activating it hands that addressto the user's configured mail application. The extension does not prefill,
read, attach, or send any message content; sending an email remains an explicit
action in that separate mail application.
Managed reply content is transmitted only when the user presses Post in an
extension-owned composer. Native create-thread and comment forms continue to
be submitted by HLTV's page.
While the user types a valid
@ prefix in the packaged preview composer, theprefix can be sent to HLTV's username-suggestion endpoint. The rest of the
draft is not sent for suggestions.
Each preview reply target can retain an independent unsaved value in its own
packaged field while the user switches composers. At most 20 such
extension-origin composer sessions exist in one preview. Closing the preview
disposes those unsaved in-memory fields.
The extension writes a forum draft to
browser.storage.local only after thesigned-in user explicitly presses Save as draft. Saved entries are scoped
to the detected numeric HLTV account and exact top-level reply, threaded-reply,
or new-topic context. Returning to a matching page can offer the entry for an
explicit restore, but the extension never overwrites a nonempty title or body
field. Saving a draft makes no network request, and the extension does not
schedule reminder notifications.
When an extension-brokered reply is confirmed, the extension removes its saved
draft only if both the stored revision and body still match the revision and
body captured for that post. A newer edit saved in another tab is retained.
Native new-topic submission cannot be confirmed by that broker, so a saved
topic remains until the user explicitly deletes it from the in-page manager.
Data sent to and received from HLTV.org
The extension can make the following HTTPS page and action requests to
www.hltv.org; the allowlisted image loads identified below can also useimg-cdn.hltv.org:
- Forum activity
- Request and data: Enabled forum-list path and pagination offset;
receives forum rows. - Trigger: Automatically for forum sources selected in settings.
- News and Matches activity
- Request and data: HLTV home-page GET; receives news and match rows.
- Trigger: When either source is selected and suitable current-page
markup or a fresh local activity cache cannot be reused; the two sources
share a refresh request. - Additional match teams
- Request and data:
/searchTeamquery containing the typed team-name
prefix; receives matching team IDs and names. - Trigger: After expanded filtering is enabled and the user types at
least two characters. - Thread preview
- Request and data: Selected HLTV thread URL; receives the thread and
comment content needed for the preview. - Trigger: When the user hovers a supported forum title or forum
notification link while previews are enabled. - Thread-preview images
- Request and data: Allowlisted HLTV gallery, flag, and team-flair image
URLs onwww.hltv.orgorimg-cdn.hltv.org; receives the selected image
bytes with ano-referrerpolicy. - Trigger: Lazily, when an enabled preview contains a supported image;
gallery images are limited to four per post and 20 per preview, while flag
and team-flair image loads share a separate 100-image per-preview limit. - Vote state and verification
- Request and data: Thread URL plus the selected thread/reply identifier;
receives current vote state. - Trigger: Before or after a managed HLTV +1 when verification is needed.
- Real HLTV +1
- Request and data: Bodyless POST to HLTV's thread or reply +1 toggle
endpoint. - Trigger: Only when the user activates or removes a real HLTV +1, or
converts a provisional local +1. - Managed reply
- Request and data: Reply text, thread identifier, optional parent-reply
identifier, and applicable form context. - Trigger: Only when the user presses Post in an extension-managed
reply composer. - Username suggestions
- Request and data: Valid username prefix.
- Trigger: While the user types a supported
@mention in the packaged
preview composer. - Block or unblock
- Request and data: Profile GET to inspect current state, followed by the
selected profile form action. - Trigger: After the user opens the optional right-click menu and chooses
Block user or Unblock user. - Selectable WAR column
- Request and data: Linked HLTV team-statistics pages; receives team wins,
draws, and losses. - Trigger: When the user starts the WAR calculation or enables WAR auto
re-fetch; merely showing the selected column and controls does not fetch
team pages. - Match-history row selector
- Request and data: Subsequent native same-player
/stats/players/matches/...offsets with the exact current non-offset
filters; receives match-history rows. Allowlisted HLTV flag and
statistics-logo images retained from those rows can load lazily from
www.hltv.orgorimg-cdn.hltv.orgwith ano-referrerpolicy. - Trigger: Automatically on a supported match-history page when the
remembered 200, 300, 400, 500, or ALL choice requires rows beyond the
current native page. - Match prediction
- Request and data: The linked
/betting/analytics/{same-match-id}/...page; receives bookmakers, match
statistics, lineup, map, and veto data for that same scheduled match. - Trigger: Automatically on a supported pre-match page while prediction
is enabled; cached data is refreshed more often as the scheduled start
approaches. Returning after the match starts can display a saved pre-match
result locally and makes no prediction request. - Overperformance Score
- Request and data: Matching
/stats/teams/ftuT-side and CT-side views
with the current page's supported filters; receives team FTU table rows. - Trigger: When the feature is enabled on a supported team FTU page and
the needed side-specific page is not already the current view. - Player map matrix
- Request and data: Filter-preserving
/stats/players/matches/...pages
and pagination; receives match-history rows. - Trigger: When enabled and the user opens its player analytics tab.
- Player consistency
- Request and data: Filter-preserving
/stats/players/matches/...pages
and pagination; receives the filtered match-history rows. - Trigger: Automatically after the user enables the feature on a
supported player overview; requests are bounded, sequential, cached in
memory, and each failed page has delayed retries. - Date-period comparison
- Request and data: The user-selected player ranking or overview
comparison URL; receives that period's displayed metrics. - Trigger: When enabled with valid comparison dates and no specific-event
filter. - Player-comparison trend graph
- Request and data: Every filter-preserving match-history page for each
available comparison player; receives dated map rows. - Trigger: Only after the user presses Fetch comparison trends on an
enhanced comparison page.
Raw comparison points, 10-map averages, optional 1-365-day trailing means, and
optional per-player straight least-squares trend lines are calculated locally
from those fetched rows. 10-map average and Trailing
daily mean are mutually exclusive transient controls; both unchecked means
raw per-match data. Trailing means use an integer 1-365-day inclusive UTC
window, default to 30 days, emit one position per shared UTC calendar day, and
leave unbridged gaps where a window contains no maps. Hover and keyboard-focus
detail popups are also rendered locally and do not make another request. The
daily span is capped at 20,000 days, and visible, keyboard-focusable markers are
sampled to at most 600 per player while the plotted lines retain the bounded
data. Bounded SVG-level nearest-point hit testing makes every finite daily date
mouse-inspectable with one reused hover indicator.
Map-matrix, comparison-trend, and match-history-selector requests are
sequential, start at least 500 ms apart, detect repeated pages and pagination
loops, and stop at 100 pages or 10,000 unique rows per filtered history. Each
failed history page is retried after 3 seconds and, if needed, once more after
5 seconds; failure of the final retry ends that operation with an error and the
row selector preserves its already loaded rows for a manual retry. Consistency starts after
500 ms and uses the same bounded, sequential, filter-preserving history loader,
cache, pagination limits, and 3-second and 5-second per-page retry delays. Parsed history is
cached in memory for up to 15 minutes, with at most four histories retained.
A comparison-period page is cached in memory for up to five minutes. That page
cache is limited to 16 entries and 8 MiB of aggregate UTF-8 serialized
content; older entries are evicted first. These memory caches disappear when
the content-script context ends.
The map matrix preserves only an allowlist of relevant statistics filters.
Unknown query parameters are not copied to generated fetch URLs. Responses
are size-bounded and parsed into detached, sanitized fragments. Only
same-origin HLTV statistics paths are accepted.
Win-adjusted-rating team requests start at least 500 ms apart. A failed team
request is retried after 3 seconds and, if needed, once more after 5 seconds.
Match prediction is deterministic and uses only the current match page and
its same-match HLTV analytics page. The default Page stats only mode ignores
bookmaker odds and provides the detailed calculation breakdown. The optional
Market-estimated mode reports the median of the valid de-vigged bookmaker
probabilities directly and never adjusts or replaces that result with page
statistics. When no valid odds are available, it reports that the odds estimate
is unavailable rather than switching modes. Changing modes is an explicit
choice saved in extension-local storage. The HLTV user poll, comments, streams,
prize pool, nationality, and live results are not prediction inputs. The
analytics response is fetched by the extension background process, limited to
4 MiB, validated against the exact match ID, teams, and scheduled timestamp,
and cached for a bounded period. The feature does not request team pages,
player pages, ranking archives, historical databases, external APIs, or any
non-HLTV service. It does not generate, refresh, or reconstruct a prediction at
or after the scheduled match start. When a matching result was calculated
beforehand, Firefox can render its frozen Page stats only or Market-estimated
snapshot on the ongoing or finished match page. That display uses only the
saved pre-match calculation, is labeled with its original calculation time,
and makes no analytics request or use of live or final-match data.
Overperformance Score is calculated locally in percentage points after the
matching filtered T-side round-win and CT-side opening-duel rows are paired by
team ID. Its cohort mean values and least-squares coefficient are derived in
the current page context; no fixed historical calibration or external dataset
is used. Its missing-side requests have a 12-second timeout and 4 MiB response
limit, must remain on the exact HLTV FTU route with the same filters and
requested side after redirects, and are parsed in a detached sanitized
fragment. Results and side rows stay in the current page context. The feature
does not use an external API or send those values anywhere.
For identity-sensitive forum-list and team-statistics requests, the extension
also validates the final URL after any same-origin redirect. Forum pages must
remain the exact requested section and offset. Team pages may change their
human-readable slug, but their numeric team ID must remain unchanged.
A local minus does not send a downvote to HLTV. If it replaces the user's
active real HLTV +1, the extension first asks HLTV to remove that +1 and
records the local
-1 only after the removal is confirmed. A provisionalpink local +1 makes no request when created or removed; the user can later
choose to convert it to a real HLTV +1.
Normal browser request information can include the user's IP address, user
agent, request time, requested HLTV path, referrer, and applicable HLTV
cookies. Firefox attaches applicable cookies to same-origin requests so HLTV
can recognize the user's existing session. The extension does not request
cookie permission and does not read, copy, or store cookie contents.
Thread-preview image elements explicitly use
no-referrer, instructingFirefox not to send a referrer on those allowlisted image loads.
No executable request is made to a developer, analytics, advertising, or
other third-party endpoint. Links that the user chooses to open are ordinary
browser navigation.
Data stored locally
Depending on the enabled features and the user's actions, Firefox
extension-private
browser.storage.local can contain:
- settings and per-source colors;
- locally selected additional match teams;
- local user tags and exact tag-hiding rules;
- thread read state and first-unread information;
- local reaction records, derived user scores, provisional local +1 records,
and bounded action-recovery state; - recent forum, news, and match activity caches;
- bounded win-adjusted-rating and related statistics caches;
- the selected match-prediction mode, a bounded refresh cache of normalized
same-match inputs, and a separate archive containing exact Page stats only
and Market-estimated snapshots for the newest 50 calculated matches; - explicitly saved, account-scoped forum reply and new-topic drafts, including
their message body, optional topic title, target context, saved revision, and
last-updated time; - saved stats-table column layouts and multi-sort definitions; and
- the optional diagnostic log described below.
Short-lived vote, reply, profile-action, and saved-draft lock metadata can be
stored in Firefox's memory-only
browser.storage.session. It contains anaction kind, validated target, tab, expiry, and random lock token. A saved-draft
lock uses the signed-in account's numeric HLTV user ID as its validated target
so saves and deletions for that account cannot race across tabs. Lock metadata
is used only to serialize local actions and is not sent over the network.
The Blocked marker shown after a successful action exists only in the
current page context and disappears when that context ends. It is not added to
extension storage.
Settings and local feature records remain until the user clears or resets
them, removes the extension's site data, or uninstalls the extension. Saved
drafts use schema 1, have no age expiry, and are limited to 50 entries, 50,000
characters per message body, and 2 MiB in aggregate across the signed-in
account's valid draft records. Reaching a limit refuses the new save; it does
not silently evict an existing draft. The in-page settings manager can revisit
a saved target and delete one or all drafts, with confirmation before deletion.
Draft titles and bodies are not included in settings, user-data, or
diagnostic-log exports. Bounded caches expire or evict entries according to
their implementation. Saved
pre-match predictions have no age expiry: the archive deterministically keeps
the newest 50 matches by original calculation time, without promoting entries
when they are viewed. An upgrade preserves compatible saved values.
Optional diagnostic log
Diagnostic logging is disabled by default. When the user explicitly enables
it, the extension stores a redacted troubleshooting log in
browser.storage.local with all of these limits:
- at most 500 entries;
- at most 256 KiB;
- at most seven days of retention; and
- duplicate nearby events can be collapsed into a counter.
The log can contain a timestamp, severity, generic event name, broad page
class such as
thread or stats, occurrence count, sanitized error name andcode, and extension-source stack frames. Free-form error messages are omitted.
It does not record draft titles or bodies, post text, usernames, tags, cookies, credentials,
raw HTML, response bodies, full URLs, query strings, fragments, IP addresses,
email addresses, or numeric profile/thread identifiers. Turning logging off
stops new records but does not silently upload or delete existing ones. The
user can clear the log or download a local JSON copy. Nothing is sent
automatically.
User-requested local exports and imports
The toolbar and in-page settings interfaces can create local JSON downloads:
- Export saved settings includes normalized extension settings, source
colors, table layouts, and saved multi-sort definitions. - Export user data includes local tags, read state, reactions, derived
scores, provisional local +1 records, and additional match teams. - Export debug log includes only the redacted bounded diagnostic record.
Saved drafts are excluded from each export and are not accepted through either
import path.
Creating an export does not send it anywhere. The user controls any later
sharing of the downloaded file. Exports can reveal private local choices and
should be reviewed before sharing.
The toolbar and in-page interfaces provide separate controls for the
saved-settings and user-data JSON formats, and reject a valid export of the
wrong kind. Import files are read only inside Firefox, limited to 5 MiB,
validated and normalized before storage, and never uploaded. Recognized
settings replace their current values while unrelated storage is preserved.
User tags, read state, reactions, provisional local +1 records, and additional
teams are merged by identity; where a record exists in both places, the newer
valid timestamp wins. The validated result is committed through one storage
batch so a partial import is not left behind.
Page-visible effects and private UI
Private settings and user-interface values are rendered in closed Shadow DOM
where practical. The packaged preview reply field is an extension-origin,
sandboxed field. HLTV page scripts cannot directly traverse those closed
roots or read their raw values through the normal DOM API.
Restoring a saved preview reply sends one bounded set-text command through the
private extension port to that packaged field. The command is accepted only
for the matching token, only within the message-body limit, and only while the
field is empty.
This is not complete invisibility. HLTV page scripts can observe effects that
must be visible on the page, such as extension host dimensions, wider layout,
hidden-comment layout, read indicators, source colors, statistics columns,
match panels, and other rendered output.
Security safeguards
- Required host access is declared through the exact
https://www.hltv.org/*content-script scope. Firefox grants that origin to
the background match-prediction broker for its validated same-match HLTV
analytics request. - Extension-generated fetch targets are validated against the HLTV origin and
expected path families. - Fetched content that can supply rendered markup is parsed with Firefox's
Sanitizer API into detached fragments before querying. Match analytics are
validated and parsed inertly for allowlisted values only; their HTML is
never inserted into the page. No fetched script or event handler executes. - Thread-preview image URLs are recovered only from sanitized inert markup and
revalidated against allowlisted HLTV origins. Gallery and flag URLs must
match expected path families, team logos must use a supported image
filename, and all image loads are bounded, lazy, and assigned a
no-referrerpolicy. - No remote executable code,
eval, code generator, analytics SDK, or
third-party JavaScript library is included. - The only general Firefox API permission is
storage. - The extension requests neither
notificationsnoralarms; saved drafts do
not create reminder notifications. - The extension is not allowed in private browsing.
Deletion and control
The settings interfaces provide controls to reset local reaction counts and
clear the diagnostic log. The in-page settings also list saved drafts and can
delete one entry or, after confirmation, all entries. Firefox's add-on settings
can remove the extension and its private storage. The user can also clear the
extension's stored data through Firefox.
Disabling a feature stops its new processing and removes its rendered UI where
supported. Some previously stored local preferences remain so they can be
restored if the feature is re-enabled; the user can remove them by clearing
extension data or uninstalling the extension.
Changes and contact
Material changes to these practices will be reflected in an updated policy
and extension release.
Questions can be sent to
plenhar@proton.me.