From c38df918410a6ea1a9751644c94cf591030899c3 Mon Sep 17 00:00:00 2001 From: Ronnie Miller Date: Thu, 10 Jul 2025 21:39:19 -0700 Subject: [PATCH] docs: Configure Segment (#8996) --- .github/workflows/deploy-docs-draft.yml | 1 + .github/workflows/deploy_gh-pages.yml | 2 + docs/docusaurus.config.js | 7 ++ docs/src/plugins/segment/analytics-page.js | 15 ++++ .../segment/data-attribute-tracking.js | 81 +++++++++++++++++++ docs/src/plugins/segment/index.js | 40 +++++++++ docs/yarn.lock | 31 ++----- 7 files changed, 152 insertions(+), 25 deletions(-) create mode 100644 docs/src/plugins/segment/analytics-page.js create mode 100644 docs/src/plugins/segment/data-attribute-tracking.js create mode 100644 docs/src/plugins/segment/index.js diff --git a/.github/workflows/deploy-docs-draft.yml b/.github/workflows/deploy-docs-draft.yml index 07ae91447..c79ace21d 100644 --- a/.github/workflows/deploy-docs-draft.yml +++ b/.github/workflows/deploy-docs-draft.yml @@ -85,6 +85,7 @@ jobs: env: BASE_URL: /langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }} FORCE_COLOR: 0 # Disable color output + SEGMENT_PUBLIC_WRITE_KEY: ${{ vars.DOCS_DRAFT_SEGMENT_PUBLIC_WRITE_KEY }} - name: Check Build Result id: buildLogFail diff --git a/.github/workflows/deploy_gh-pages.yml b/.github/workflows/deploy_gh-pages.yml index 774926e5c..e6eae5856 100644 --- a/.github/workflows/deploy_gh-pages.yml +++ b/.github/workflows/deploy_gh-pages.yml @@ -25,6 +25,8 @@ jobs: run: cd docs && yarn install - name: Build website run: cd docs && yarn build + env: + SEGMENT_PUBLIC_WRITE_KEY: ${{ vars.DOCS_PROD_SEGMENT_PUBLIC_WRITE_KEY }} # Popular action to deploy to GitHub Pages: # Docs: https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-docusaurus diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index db98e4cf7..22339eeb3 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -130,6 +130,7 @@ const config = { plugins: [ ["docusaurus-node-polyfills", { excludeAliases: ["console"] }], "docusaurus-plugin-image-zoom", + ["./src/plugins/segment", { segmentPublicWriteKey: process.env.SEGMENT_PUBLIC_WRITE_KEY, allowedInDev: true }], [ "@docusaurus/plugin-client-redirects", { @@ -335,6 +336,8 @@ const config = { className: "header-github-link", target: "_blank", rel: null, + 'data-event': 'Docs.langflow.org - Social Clicked', + 'data-platform': 'github' }, { position: "right", @@ -342,6 +345,8 @@ const config = { className: "header-twitter-link", target: "_blank", rel: null, + 'data-event': 'Docs.langflow.org - Social Clicked', + 'data-platform': 'x' }, { position: "right", @@ -349,6 +354,8 @@ const config = { className: "header-discord-link", target: "_blank", rel: null, + 'data-event': 'Docs.langflow.org - Social Clicked', + 'data-platform': 'discord' }, ], }, diff --git a/docs/src/plugins/segment/analytics-page.js b/docs/src/plugins/segment/analytics-page.js new file mode 100644 index 000000000..d2f1b3602 --- /dev/null +++ b/docs/src/plugins/segment/analytics-page.js @@ -0,0 +1,15 @@ +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; + +// Client module for tracking page views on route changes +export function onRouteDidUpdate({location, previousLocation}) { + // Only track page views in the browser and when the path actually changes + if ( + ExecutionEnvironment.canUseDOM && + previousLocation && + location.pathname !== previousLocation.pathname && + window.analytics && + window.analytics.page + ) { + window.analytics.page(); + } +} diff --git a/docs/src/plugins/segment/data-attribute-tracking.js b/docs/src/plugins/segment/data-attribute-tracking.js new file mode 100644 index 000000000..00a861e20 --- /dev/null +++ b/docs/src/plugins/segment/data-attribute-tracking.js @@ -0,0 +1,81 @@ +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; + +let isDataAttributeTrackingInitialized = false; + +/** + * Automatic click tracking using data attributes for Docusaurus + * + * Usage: Add data-event and other data-* attributes to any clickable element. + * The tracker will automatically send events to Segment when clicked. + * + * Example in navbar config: + * { + * href: "https://github.com/langflow-ai/langflow", + * 'data-event': 'GitHub Link Clicked', + * 'data-source': 'navbar', + * 'data-category': 'social' + * } + * + * This will automatically call: + * window.analytics.track("GitHub Link Clicked", { + * source: "navbar", + * category: "social", + * url: "https://github.com/langflow-ai/langflow", + * page: "/current-page" + * }) + */ +function initializeDataAttributeTracking() { + // Only run on client side and prevent duplicate initialization + if (!ExecutionEnvironment.canUseDOM || isDataAttributeTrackingInitialized) return; + + const handleClick = (event) => { + const target = event.target; + const trackingElement = target.closest('[data-event]'); + + if (!trackingElement) return; + + const eventName = trackingElement.dataset.event; + if (!eventName) return; + + // Extract all data-* attributes (except data-event itself) + const properties = {}; + + Object.keys(trackingElement.dataset).forEach(key => { + if (key !== 'event') { + // Convert camelCase to snake_case for consistency + const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase(); + properties[snakeKey] = trackingElement.dataset[key]; + } + }); + + // Track the event + if (window.analytics && typeof window.analytics.track === 'function') { + window.analytics.track(eventName, properties); + } else { + console.warn('Analytics not available for tracking:', eventName, properties); + } + }; + + // Remove existing listener if it exists + document.removeEventListener('click', handleClick); + + // Add the new listener + document.addEventListener('click', handleClick); + + // Mark as initialized + isDataAttributeTrackingInitialized = true; +} + +// Initialize on DOM ready +if (ExecutionEnvironment.canUseDOM) { + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initializeDataAttributeTracking); + } else { + initializeDataAttributeTracking(); + } + + // Re-initialize on route changes for SPA navigation + window.addEventListener('popstate', () => { + setTimeout(initializeDataAttributeTracking, 100); + }); +} diff --git a/docs/src/plugins/segment/index.js b/docs/src/plugins/segment/index.js new file mode 100644 index 000000000..b6e22fc9e --- /dev/null +++ b/docs/src/plugins/segment/index.js @@ -0,0 +1,40 @@ +// Custom Docusaurus plugin to inject Segment analytics +function pluginSegment(context, options = {}) { + const isProd = process.env.NODE_ENV === "production" || options.allowedInDev; + const segmentPublicWriteKey = options.segmentPublicWriteKey; + + if (!segmentPublicWriteKey) { + console.warn('Segment plugin: No write key provided. Analytics will not be initialized.'); + return { name: 'docusaurus-plugin-segment' }; + } + + return { + name: 'docusaurus-plugin-segment', + + getClientModules() { + return isProd ? [require.resolve('./analytics-page'), require.resolve('./data-attribute-tracking')] : []; + }, + + injectHtmlTags() { + if (!isProd) { + return {}; + } + + return { + headTags: [ + { + tagName: 'script', + innerHTML: ` + !function(){var i="analytics",analytics=window[i]=window[i]||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","screen","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware","register"];analytics.factory=function(e){return function(){if(window[i].initialized)return window[i][e].apply(window[i],arguments);var n=Array.prototype.slice.call(arguments);if(["track","screen","alias","group","page","identify"].indexOf(e)>-1){var c=document.querySelector("link[rel='canonical']");n.push({__t:"bpc",c:c&&c.getAttribute("href")||void 0,p:location.pathname,u:location.href,s:location.search,t:document.title,r:document.referrer})}n.unshift(e);analytics.push(n);return analytics}};for(var n=0;n