Skip to content

Conversation

@misrasaurabh1
Copy link
Contributor

@misrasaurabh1 misrasaurabh1 commented Oct 24, 2025

PR Type

Enhancement


Description

  • Add Crisp chat widget script

  • Integrate PostHog analytics initialization

  • Configure external script loading and options


Diagram Walkthrough

flowchart LR
  Docs["Docs site"] -- "loads" --> CrispJS["docs/crisp.js"]
  Docs -- "loads" --> PostHogJS["docs/posthog.js"]
  CrispJS -- "injects" --> CrispClient["Crisp chat client"]
  PostHogJS -- "init" --> PostHogClient["PostHog analytics"]
Loading

File Walkthrough

Relevant files
Enhancement
crisp.js
Add Crisp chat loader for docs                                                     

docs/crisp.js

  • Add Crisp loader snippet
  • Set CRISP_WEBSITE_ID
  • Inject async script from client.crisp.chat
+1/-0     
posthog.js
Integrate PostHog analytics initialization                             

docs/posthog.js

  • Add PostHog bootstrap snippet
  • Initialize with API key and host
  • Configure defaults and person profiles
  • Load array.js asynchronously with CORS
+6/-0     

Signed-off-by: Saurabh Misra <misra.saurabh1@gmail.com>
@github-actions
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 Security concerns

Sensitive information exposure:
The PostHog API key and Crisp website ID are embedded in client JS. While these IDs can be public in many setups, confirm that the PostHog key is a client-side public key with appropriate permissions and not a server secret. Consider documenting that these values are public and scoping access in PostHog. Additionally, loading third-party scripts from remote origins (crisp.chat and posthog assets) introduces supply-chain risk; consider Subresource Integrity (SRI) where possible and a Content Security Policy that restricts script sources.

⚡ Recommended focus areas for review

Hardcoded ID

The Crisp website ID is hardcoded, which makes environment-specific configuration difficult and risks accidental reuse across environments. Consider sourcing from environment variables or a build-time config.

window.$crisp=[];window.CRISP_WEBSITE_ID="3e855999-42a1-4543-accf-afc369edfca0";(function(){d=document;s=d.createElement("script");s.src="https://client.crisp.chat/l.js";s.async=1;d.getElementsByTagName("head")[0].appendChild(s);})();
Secret In Code

The PostHog project API key appears hardcoded in the client script. Verify that this is a public client key and acceptable to expose. If not, move to environment/config and ensure it's scoped appropriately.

posthog.init('phc_aUO790jHd7z1SXwsYCz8dRApxueplZlZWeDSpKc5hol', {
    api_host: 'https://us.i.posthog.com',
    defaults: '2025-05-24',
    person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well
})
Config Typo

The 'defaults' option is not a standard PostHog init setting. Confirm intended option name (e.g., 'loaded', 'capture_pageview', or custom config) or remove to avoid no-op/misconfig.

defaults: '2025-05-24',

@github-actions
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Remove invalid init option

The defaults option is not a valid PostHog init setting and will be ignored or could
cause unexpected behavior. Remove it to avoid misconfiguration and potential runtime
warnings.

docs/posthog.js [2-6]

 posthog.init('phc_aUO790jHd7z1SXwsYCz8dRApxueplZlZWeDSpKc5hol', {
     api_host: 'https://us.i.posthog.com',
-    defaults: '2025-05-24',
     person_profiles: 'identified_only', // or 'always' to create profiles for anonymous users as well
 })
Suggestion importance[1-10]: 8

__

Why: The defaults key isn't a recognized PostHog init option; removing it prevents misconfiguration and potential runtime issues, directly improving correctness.

Medium
Possible issue
Prevent unintended global variables

Avoid leaking globals by declaring d and s with var or const inside the IIFE. Also,
reference window.document to be explicit and prevent shadowing.

docs/crisp.js [1]

-window.$crisp=[];window.CRISP_WEBSITE_ID="3e855999-42a1-4543-accf-afc369edfca0";(function(){d=document;s=d.createElement("script");s.src="https://client.crisp.chat/l.js";s.async=1;d.getElementsByTagName("head")[0].appendChild(s);})();
+window.$crisp=[];window.CRISP_WEBSITE_ID="3e855999-42a1-4543-accf-afc369edfca0";(function(){var d=window.document;var s=d.createElement("script");s.src="https://client.crisp.chat/l.js";s.async=true;d.getElementsByTagName("head")[0].appendChild(s);})();
Suggestion importance[1-10]: 7

__

Why: Correctly identifies undeclared d and s leaking to globals and proposes a safe, minimal fix without changing behavior; moderate impact on robustness.

Medium
Guard asset host replacement

When api_host is a custom domain, the
.replace(".i.posthog.com","-assets.i.posthog.com") call can yield a wrong script
URL. Add a guard to only replace when the host matches PostHog’s domain to prevent
loading failures.

docs/posthog.js [1]

-!function(t,e){var o,n,p,r;e.__SV||(window.posthog && window.posthog.__loaded)||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init yi Fr Mr mi Rr Or capture Li calculateEventProperties Dr register register_once register_for_session unregister unregister_for_session zr getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey displaySurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Nr jr createPersonProfile Ur Tr Hr opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing get_explicit_consent_status is_capturing clear_opt_in_out_capturing Ar debug L Lr getPageViewId captureTraceFeedback captureTraceMetric $r".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
+!function(t,e){var o,n,p,r;e.__SV||(window.posthog && window.posthog.__loaded)||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0;var host=s.api_host;var assetHost=/\.i\.posthog\.com$/.test(host) ? host.replace(/\.i\.posthog\.com$/,"-assets.i.posthog.com") : host; p.src=assetHost+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init yi Fr Mr mi Rr Or capture Li calculateEventProperties Dr register register_once register_for_session unregister unregister_for_session zr getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey displaySurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Nr jr createPersonProfile Ur Tr Hr opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing get_explicit_consent_status is_capturing clear_opt_in_out_capturing Ar debug L Lr getPageViewId captureTraceFeedback captureTraceMetric $r".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
Suggestion importance[1-10]: 6

__

Why: The guard makes URL replacement safer for custom domains, reducing risk of loading a wrong script; however, impact is situational and changes vendor snippet slightly.

Low

@misrasaurabh1 misrasaurabh1 merged commit c53245a into main Oct 24, 2025
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants