Skip to content

feat: enhance global configuration handling and improve attribute retrieval logic#4198

Open
Yashh56 wants to merge 4 commits into
umami-software:devfrom
Yashh56:feat/globalconfig
Open

feat: enhance global configuration handling and improve attribute retrieval logic#4198
Yashh56 wants to merge 4 commits into
umami-software:devfrom
Yashh56:feat/globalconfig

Conversation

@Yashh56
Copy link
Copy Markdown
Contributor

@Yashh56 Yashh56 commented Apr 23, 2026

This pull request updates the tracker initialization logic to allow configuration via a global umamiConfig object in addition to the existing method of using data- attributes on the script tag. This makes it possible to initialize the tracker even when the script tag is not present, and allows for more flexible configuration.

Key changes:

Configuration improvements:

  • Added support for a global umamiConfig object to provide configuration values (such as websiteId and hostUrl) as an alternative to data- attributes on the script tag. This enables initialization without requiring the script tag to be present. [1] [2]

  • Updated the config function to prioritize values from umamiConfig, falling back to data- attributes if not found. Also added a utility to convert config keys from kebab-case to camelCase for compatibility.

Robustness improvements:

  • Modified logic to safely handle cases where currentScript is not available, preventing errors during initialization and when constructing the API host URL. [1] [2]

Closes: #4177

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 23, 2026

@Yashh56 is attempting to deploy a commit to the Umami Software Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 23, 2026

Greptile Summary

This PR adds a window.umamiConfig global object as an alternative to data- attributes on the script tag, enabling tracker initialization without a <script> element. It also adds null-safety around currentScript accesses and fixes beforeSend to accept a direct function reference from umamiConfig.

The null-stringification bug from the prior review thread is fully resolved (!= null), and the before-send function pass-through is now explicitly handled. The remaining open concern from the prior thread — non-before-send config fields (e.g. hostUrl, credentials, domains) receiving function values — is still present, though it requires deliberate user misconfiguration to trigger.

Confidence Score: 4/5

Safe to merge after clarifying whether the recorder's currentScript guard is intentionally not updated to support umamiConfig-only usage.

The core logic is correct and the two previously flagged issues are partially or fully resolved. The recorder/tracker inconsistency is the main unresolved concern — it silently disables recordings for umamiConfig-only setups, which contradicts the stated goal of enabling initialization without requiring the script tag.

src/recorder/index.js — early-exit guard on line 6 was not updated to mirror the tracker's umamiConfig fallback.

Important Files Changed

Filename Overview
src/tracker/index.js Adds umamiConfig global config support, safe currentScript null-guards, and a correct beforeSend function pass-through. The two previously-flagged concerns (null stringification, function pass-through for non-before-send fields) are partially addressed; the former is fully fixed, the latter still applies to fields like hostUrl/credentials/domains if a function is erroneously passed.
src/recorder/index.js Gains umamiConfig object support for config values, but retains the hard if (!currentScript) return guard, making it inconsistent with the tracker's new umamiConfig-only initialization path.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Script loads] --> B{currentScript present?}
    B -- Yes --> C[Bind attr to currentScript]
    B -- No --> D{umamiConfig.websiteId set?}
    D -- No --> E[Return / abort]
    D -- Yes --> F[attr returns null for all]
    C --> G[config lookup]
    F --> G
    G --> H{globalConfig camelKey != null?}
    H -- Yes --> I{before-send and typeof fn?}
    I -- Yes --> J[Return function directly]
    I -- No --> K{Array value?}
    K -- Yes --> L[join with comma]
    K -- No --> M[String coerce]
    H -- No --> N[Read data-attr from script tag]
    J --> O[Extract website, hostUrl, beforeSend, etc]
    L --> O
    M --> O
    N --> O
    O --> P[Tracker initializes and sends events]
Loading

Reviews (4): Last reviewed commit: "Refactor global configuration handling t..." | Re-trigger Greptile

Comment thread src/tracker/index.js
@Yashh56
Copy link
Copy Markdown
Contributor Author

Yashh56 commented Apr 23, 2026

@greptileai

@Yashh56 Yashh56 changed the title Enhance global configuration handling and improve attribute retrieval… feat: enhance global configuration handling and improve attribute retrieval logic Apr 23, 2026
@julianwitzel
Copy link
Copy Markdown

julianwitzel commented Apr 24, 2026

Nice work on this — the overall approach looks solid and covers the main use case from the feature request well. A few follow-ups I’d suggest:

1. domains as an array gets silently coerced

The feature request example used domains: ['mywebsite.com'], but String(['a.com', 'b.com']) happens to work only because arrays stringify comma-separated. Entries containing commas or whitespace would break the split. Either handle arrays explicitly in config():

if (globalConfig[camelKey] != null) {
  const v = globalConfig[camelKey];
  return Array.isArray(v) ? v.join(',') : String(v);
}

…or document clearly that domains must be a comma-separated string even when set via umamiConfig.

2. beforeSend still expects a string reference

The tracker reads window[beforeSend], so umamiConfig.beforeSend has to be a function name as a string, not the function itself. That’s a GTM sandbox hurdle — setInWindow can set the name, but getting the callback function onto window from a Custom Template is awkward. Not blocking for most GTM Template use cases (most people won’t need beforeSend), but ideally globalConfig.beforeSend would also accept a function directly, e.g.:

const callback = typeof beforeSend === 'function'
  ? beforeSend
  : window[beforeSend];

3. Recorder needs the same treatment

recorder.js (Session Replay) is a separate script with its own data-* attributes (data-sample-rate, data-mask-level, data-max-duration) and currently has the exact same GTM Custom Template sandbox limitation this PR fixes for the tracker. Covering both would enable a complete “Umami via GTM” setup — tracker + recorder. Happy to open a follow-up PR specifically for the recorder if you’d prefer to keep this one focused.
Minor: Worth noting in the docs that an explicit autoTrack: false in umamiConfig overrides data-auto-track="true" on the script tag (precedence: globalConfig > data-attr). That’s probably the intended behavior, but currently undocumented.

@Yashh56
Copy link
Copy Markdown
Contributor Author

Yashh56 commented Apr 24, 2026

@greptileai

Comment thread src/tracker/index.js
@Yashh56
Copy link
Copy Markdown
Contributor Author

Yashh56 commented Apr 24, 2026

@greptileai

@Yashh56
Copy link
Copy Markdown
Contributor Author

Yashh56 commented May 5, 2026

Hey @mikecao and @franciscao633, could you please take a look and share your feedback?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants