feat: trim integration pages from 75 to 25 + migrate to MDX
- Add dedicatedPage flag to integration registry (25 true, 50 false) - Delete hardcoded nextjs/react/vue/wordpress route pages (wrong metadata) - Hub page routes non-dedicated integrations to /integrations/script-tag - Add 301 redirects for 50 removed slugs → /integrations/script-tag - Migrate guide content from TSX to MDX (content/integrations/*.mdx) - Add gray-matter, next-mdx-remote, remark-gfm dependencies - Add content loader (lib/integration-content.ts) matching ciphera-website pattern - Add prebuild script for integration guide index generation - Sitemap reduced from 83 to 35 URLs with real lastmod dates - Remove seoDescription from registry (now in MDX frontmatter)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,5 +1,8 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# auto-generated
|
||||||
|
/lib/integration-guides.gen.ts
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
/node_modules
|
||||||
/.pnp
|
/.pnp
|
||||||
|
|||||||
@@ -1,46 +1,56 @@
|
|||||||
/**
|
/**
|
||||||
* @file Dynamic route for individual integration guide pages.
|
* @file Dynamic route for individual integration guide pages.
|
||||||
*
|
*
|
||||||
* Handles all 50 integration routes via [slug].
|
* Renders MDX content from content/integrations/*.mdx via next-mdx-remote.
|
||||||
* Exports generateStaticParams for static generation and
|
* Exports generateStaticParams for static generation and
|
||||||
* generateMetadata for per-page SEO (title, description, OG, JSON-LD).
|
* generateMetadata for per-page SEO (title, description, OG, JSON-LD).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Metadata } from 'next'
|
import type { Metadata } from 'next'
|
||||||
import { notFound } from 'next/navigation'
|
import { notFound } from 'next/navigation'
|
||||||
|
import { MDXRemote } from 'next-mdx-remote/rsc'
|
||||||
|
import remarkGfm from 'remark-gfm'
|
||||||
|
import { CodeBlock } from '@ciphera-net/ui'
|
||||||
import { integrations, getIntegration } from '@/lib/integrations'
|
import { integrations, getIntegration } from '@/lib/integrations'
|
||||||
import { getGuideContent } from '@/lib/integration-guides'
|
import { getIntegrationGuide } from '@/lib/integration-content'
|
||||||
import { IntegrationGuide } from '@/components/IntegrationGuide'
|
import { IntegrationGuide } from '@/components/IntegrationGuide'
|
||||||
|
|
||||||
// * ─── Static Params ───────────────────────────────────────────────
|
// * ─── MDX Components ────────────────────────────────────────────
|
||||||
export function generateStaticParams() {
|
const mdxComponents = {
|
||||||
return integrations.map((i) => ({ slug: i.id }))
|
CodeBlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
// * ─── SEO Metadata ────────────────────────────────────────────────
|
// * ─── Static Params ─────────────────────────────────────────────
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return integrations
|
||||||
|
.filter((i) => i.dedicatedPage)
|
||||||
|
.map((i) => ({ slug: i.id }))
|
||||||
|
}
|
||||||
|
|
||||||
|
// * ─── SEO Metadata ──────────────────────────────────────────────
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: Promise<{ slug: string }>
|
params: Promise<{ slug: string }>
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
||||||
const { slug } = await params
|
const { slug } = await params
|
||||||
const integration = getIntegration(slug)
|
const guide = getIntegrationGuide(slug)
|
||||||
if (!integration) return {}
|
if (!guide) return {}
|
||||||
|
|
||||||
const title = `How to Add Pulse Analytics to ${integration.name} | Pulse by Ciphera`
|
const title = `How to Add Pulse Analytics to ${guide.title} | Pulse by Ciphera`
|
||||||
const description = integration.seoDescription
|
const description = guide.description
|
||||||
const url = `https://pulse.ciphera.net/integrations/${integration.id}`
|
const url = `https://pulse.ciphera.net/integrations/${guide.slug}`
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
keywords: [
|
keywords: [
|
||||||
`${integration.name} analytics`,
|
`${guide.title} analytics`,
|
||||||
`${integration.name} Pulse`,
|
`${guide.title} Pulse`,
|
||||||
'privacy-first analytics',
|
'privacy-first analytics',
|
||||||
'website analytics',
|
'website analytics',
|
||||||
'Ciphera Pulse',
|
'Ciphera Pulse',
|
||||||
integration.name,
|
guide.title,
|
||||||
],
|
],
|
||||||
alternates: { canonical: url },
|
alternates: { canonical: url },
|
||||||
openGraph: {
|
openGraph: {
|
||||||
@@ -58,21 +68,19 @@ export async function generateMetadata({ params }: PageProps): Promise<Metadata>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// * ─── Page Component ──────────────────────────────────────────────
|
// * ─── Page Component ────────────────────────────────────────────
|
||||||
export default async function IntegrationPage({ params }: PageProps) {
|
export default async function IntegrationPage({ params }: PageProps) {
|
||||||
const { slug } = await params
|
const { slug } = await params
|
||||||
const integration = getIntegration(slug)
|
const integration = getIntegration(slug)
|
||||||
if (!integration) return notFound()
|
const guide = getIntegrationGuide(slug)
|
||||||
|
if (!integration || !guide) return notFound()
|
||||||
const content = getGuideContent(slug)
|
|
||||||
if (!content) return notFound()
|
|
||||||
|
|
||||||
// * HowTo JSON-LD for rich search snippets
|
// * HowTo JSON-LD for rich search snippets
|
||||||
const jsonLd = {
|
const jsonLd = {
|
||||||
'@context': 'https://schema.org',
|
'@context': 'https://schema.org',
|
||||||
'@type': 'HowTo',
|
'@type': 'HowTo',
|
||||||
name: `How to Add Pulse Analytics to ${integration.name}`,
|
name: `How to Add Pulse Analytics to ${integration.name}`,
|
||||||
description: integration.seoDescription,
|
description: guide.description,
|
||||||
step: [
|
step: [
|
||||||
{
|
{
|
||||||
'@type': 'HowToStep',
|
'@type': 'HowToStep',
|
||||||
@@ -104,7 +112,11 @@ export default async function IntegrationPage({ params }: PageProps) {
|
|||||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||||
/>
|
/>
|
||||||
<IntegrationGuide integration={integration}>
|
<IntegrationGuide integration={integration}>
|
||||||
{content}
|
<MDXRemote
|
||||||
|
source={guide.content}
|
||||||
|
components={mdxComponents}
|
||||||
|
options={{ mdxOptions: { remarkPlugins: [remarkGfm] } }}
|
||||||
|
/>
|
||||||
</IntegrationGuide>
|
</IntegrationGuide>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
|
||||||
|
|
||||||
export default function NextJsIntegrationPage() {
|
|
||||||
return (
|
|
||||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
|
||||||
{/* * --- ATMOSPHERE (Background) --- */}
|
|
||||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
|
||||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
|
||||||
<div
|
|
||||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
|
||||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
|
||||||
<Link
|
|
||||||
href="/integrations"
|
|
||||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
|
||||||
>
|
|
||||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
|
||||||
Back to Integrations
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-8">
|
|
||||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
|
||||||
<svg viewBox="0 0 128 128" className="w-10 h-10 invert">
|
|
||||||
<path d="M64 0C28.7 0 0 28.7 0 64s28.7 64 64 64 64-28.7 64-64S99.3 0 64 0zm27.6 93.9c-.8.9-2.2 1-3.1.2L42.8 52.8V88c0 1.3-1.1 2.3-2.3 2.3h-7.4c-1.3 0-2.3-1.1-2.3-2.3V40c0-1.3 1.1-2.3 2.3-2.3h7.4c1 0 1.9.6 2.2 1.5l48.6 44.8V40c0-1.3 1.1-2.3 2.3-2.3h7.4c1.3 0 2.3 1.1 2.3 2.3v48c0 1.3-1.1 2.3-2.3 2.3h-6.8c-.9 0-1.7-.5-2.1-1.3z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">
|
|
||||||
Next.js Integration
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="prose prose-invert max-w-none">
|
|
||||||
<p className="lead text-xl text-neutral-400">
|
|
||||||
The best way to add Pulse to your Next.js application is using the built-in <code>next/script</code> component.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr className="my-8 border-neutral-800" />
|
|
||||||
|
|
||||||
<h3>Using App Router (Recommended)</h3>
|
|
||||||
<p>
|
|
||||||
Add the script to your root layout file (usually <code>app/layout.tsx</code> or <code>app/layout.js</code>).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
|
||||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
|
||||||
<span className="text-xs text-neutral-400 font-mono">app/layout.tsx</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 overflow-x-auto">
|
|
||||||
<pre className="text-sm font-mono text-neutral-300">
|
|
||||||
{`import Script from 'next/script'
|
|
||||||
|
|
||||||
export default function RootLayout({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<Script
|
|
||||||
defer
|
|
||||||
src="https://pulse.ciphera.net/script.js"
|
|
||||||
data-domain="your-site.com"
|
|
||||||
strategy="afterInteractive"
|
|
||||||
/>
|
|
||||||
</head>
|
|
||||||
<body>{children}</body>
|
|
||||||
</html>
|
|
||||||
)
|
|
||||||
}`}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Using Pages Router</h3>
|
|
||||||
<p>
|
|
||||||
If you are using the older Pages Router, add the script to your custom <code>_app.tsx</code> or <code>_document.tsx</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
|
||||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
|
||||||
<span className="text-xs text-neutral-400 font-mono">pages/_app.tsx</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 overflow-x-auto">
|
|
||||||
<pre className="text-sm font-mono text-neutral-300">
|
|
||||||
{`import Script from 'next/script'
|
|
||||||
import type { AppProps } from 'next/app'
|
|
||||||
|
|
||||||
export default function App({ Component, pageProps }: AppProps) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Script
|
|
||||||
defer
|
|
||||||
src="https://pulse.ciphera.net/script.js"
|
|
||||||
data-domain="your-site.com"
|
|
||||||
strategy="afterInteractive"
|
|
||||||
/>
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}`}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Configuration Options</h3>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<strong>data-domain</strong>: The domain name you added to your Pulse dashboard (e.g., <code>example.com</code>).
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>src</strong>: The URL of our tracking script: <code>https://pulse.ciphera.net/script.js</code>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<strong>strategy</strong>: We recommend <code>afterInteractive</code> to ensure it loads quickly without blocking hydration.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -244,7 +244,7 @@ export default function IntegrationsPage() {
|
|||||||
transition={{ duration: 0.4, delay: i * 0.05 }}
|
transition={{ duration: 0.4, delay: i * 0.05 }}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/integrations/${integration!.id}`}
|
href={integration!.dedicatedPage ? `/integrations/${integration!.id}` : '/integrations/script-tag'}
|
||||||
className="group flex items-center gap-3 p-4 bg-neutral-900/50 backdrop-blur-sm border border-neutral-800 rounded-xl hover:border-brand-orange/50 transition-all duration-300 hover:-translate-y-0.5 hover:shadow-lg h-full"
|
className="group flex items-center gap-3 p-4 bg-neutral-900/50 backdrop-blur-sm border border-neutral-800 rounded-xl hover:border-brand-orange/50 transition-all duration-300 hover:-translate-y-0.5 hover:shadow-lg h-full"
|
||||||
>
|
>
|
||||||
<div className="p-2 bg-neutral-800 rounded-lg shrink-0 group-hover:scale-110 transition-transform duration-300 [&_svg]:w-6 [&_svg]:h-6">
|
<div className="p-2 bg-neutral-800 rounded-lg shrink-0 group-hover:scale-110 transition-transform duration-300 [&_svg]:w-6 [&_svg]:h-6">
|
||||||
@@ -283,7 +283,7 @@ export default function IntegrationsPage() {
|
|||||||
transition={{ duration: 0.5, delay: i * 0.05 }}
|
transition={{ duration: 0.5, delay: i * 0.05 }}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/integrations/${integration.id}`}
|
href={integration.dedicatedPage ? `/integrations/${integration.id}` : '/integrations/script-tag'}
|
||||||
className="group relative p-6 bg-neutral-900/50 backdrop-blur-sm border border-neutral-800 rounded-2xl hover:border-brand-orange/50 transition-all duration-300 hover:-translate-y-1 hover:shadow-xl block h-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange focus-visible:ring-offset-2"
|
className="group relative p-6 bg-neutral-900/50 backdrop-blur-sm border border-neutral-800 rounded-2xl hover:border-brand-orange/50 transition-all duration-300 hover:-translate-y-1 hover:shadow-xl block h-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange focus-visible:ring-offset-2"
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between mb-6">
|
<div className="flex items-start justify-between mb-6">
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
|
||||||
|
|
||||||
export default function ReactIntegrationPage() {
|
|
||||||
return (
|
|
||||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
|
||||||
{/* * --- ATMOSPHERE (Background) --- */}
|
|
||||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
|
||||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
|
||||||
<div
|
|
||||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
|
||||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
|
||||||
<Link
|
|
||||||
href="/integrations"
|
|
||||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
|
||||||
>
|
|
||||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
|
||||||
Back to Integrations
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-8">
|
|
||||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
|
||||||
<svg viewBox="0 0 128 128" className="w-10 h-10 text-[#61DAFB] fill-current">
|
|
||||||
<path d="M64 10.6c18.4 0 34.6 5.8 44.6 14.8 6.4 5.8 10.2 12.8 10.2 20.6 0 21.6-28.6 41.2-64 41.2-1.6 0-3.2-.1-4.8-.2-1.2 10.8-6.2 20.2-13.8 27.6-8.8 8.6-20.6 13.4-33.2 13.4-2.2 0-4.4-.2-6.4-.4 10.2-12.8 15.6-29.2 15.6-46.2 0-2.6-.2-5.2-.4-7.8 13.6-1.6 26.2-5.4 37.4-11 11.2-5.6 20.2-13 26.2-21.4-6.4-5.8-15.4-10-25.6-12.2-10.2-2.2-21.4-3.4-33-3.4-1.6 0-3.2.1-4.8.2 1.2-10.8 6.2-20.2 13.8-27.6 8.8-8.6 20.6-13.4 33.2-13.4 2.2 0 4.4.2 6.4.4-10.2 12.8-15.6 29.2-15.6 46.2 0 2.6.2 5.2.4 7.8-13.6 1.6-26.2 5.4-37.4 11-11.2 5.6-20.2 13-26.2 21.4 6.4 5.8 15.4 10 25.6 12.2 10.2 2.2 21.4 3.4 33 3.4 1.6 0 3.2-.1 4.8-.2-1.2 10.8-6.2 20.2-13.8 27.6-8.8 8.6-20.6 13.4-33.2 13.4-2.2 0-4.4-.2-6.4-.4 10.2-12.8 15.6-29.2 15.6-46.2 0-2.6-.2-5.2-.4-7.8 13.6-1.6 26.2-5.4 37.4-11zm-33.4 62c-11.2 5.6-20.2 13-26.2 21.4 6.4 5.8 15.4 10 25.6 12.2 10.2 2.2 21.4 3.4 33 3.4 1.6 0 3.2-.1 4.8-.2-1.2 10.8-6.2 20.2-13.8 27.6-8.8 8.6-20.6 13.4-33.2 13.4-2.2 0-4.4-.2-6.4-.4 10.2-12.8 15.6-29.2 15.6-46.2 0-2.6-.2-5.2-.4-7.8 13.6-1.6 26.2-5.4 37.4-11zm-15.2-16.6c-6.4-5.8-10.2-12.8-10.2-20.6 0-21.6 28.6-41.2 64-41.2 1.6 0 3.2.1 4.8.2 1.2-10.8 6.2-20.2 13.8-27.6 8.8-8.6 20.6-13.4 33.2-13.4 2.2 0 4.4.2 6.4.4-10.2 12.8-15.6 29.2-15.6 46.2 0 2.6.2 5.2.4 7.8-13.6 1.6-26.2 5.4-37.4 11-11.2 5.6-20.2 13-26.2 21.4 6.4 5.8 15.4 10 25.6 12.2 10.2 2.2 21.4 3.4 33 3.4 1.6 0 3.2-.1 4.8-.2-1.2 10.8-6.2 20.2-13.8 27.6-8.8 8.6-20.6 13.4-33.2 13.4-2.2 0-4.4-.2-6.4-.4 10.2-12.8 15.6-29.2 15.6-46.2 0-2.6-.2-5.2-.4-7.8z" />
|
|
||||||
<circle cx="64" cy="64" r="10.6" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">
|
|
||||||
React Integration
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="prose prose-invert max-w-none">
|
|
||||||
<p className="lead text-xl text-neutral-400">
|
|
||||||
For standard React SPAs (Create React App, Vite, etc.), you can simply add the script tag to your <code>index.html</code>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr className="my-8 border-neutral-800" />
|
|
||||||
|
|
||||||
<h3>Method 1: index.html (Recommended)</h3>
|
|
||||||
<p>
|
|
||||||
The simplest way is to add the script tag directly to the <code><head></code> of your <code>index.html</code> file.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
|
||||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
|
||||||
<span className="text-xs text-neutral-400 font-mono">public/index.html</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 overflow-x-auto">
|
|
||||||
<pre className="text-sm font-mono text-neutral-300">
|
|
||||||
{`<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
|
|
||||||
<!-- Pulse Analytics -->
|
|
||||||
<script
|
|
||||||
defer
|
|
||||||
data-domain="your-site.com"
|
|
||||||
src="https://pulse.ciphera.net/script.js"
|
|
||||||
></script>
|
|
||||||
|
|
||||||
<title>My React App</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="root"></div>
|
|
||||||
</body>
|
|
||||||
</html>`}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Method 2: Programmatic Injection</h3>
|
|
||||||
<p>
|
|
||||||
If you need to load the script dynamically (e.g., only in production), you can use a <code>useEffect</code> hook in your main App component.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
|
||||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
|
||||||
<span className="text-xs text-neutral-400 font-mono">src/App.tsx</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 overflow-x-auto">
|
|
||||||
<pre className="text-sm font-mono text-neutral-300">
|
|
||||||
{`import { useEffect } from 'react'
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
useEffect(() => {
|
|
||||||
// Only load in production
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
const script = document.createElement('script')
|
|
||||||
script.defer = true
|
|
||||||
script.setAttribute('data-domain', 'your-site.com')
|
|
||||||
script.src = 'https://pulse.ciphera.net/script.js'
|
|
||||||
document.head.appendChild(script)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="App">
|
|
||||||
<h1>Hello World</h1>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}`}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
147
app/integrations/script-tag/page.tsx
Normal file
147
app/integrations/script-tag/page.tsx
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import type { Metadata } from 'next'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
||||||
|
import { CodeBlock } from '@ciphera-net/ui'
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Add Pulse Analytics to Any Website | Pulse by Ciphera',
|
||||||
|
description: 'Add privacy-first analytics to any website with a single script tag. Works with any platform, CMS, or framework.',
|
||||||
|
alternates: { canonical: 'https://pulse.ciphera.net/integrations/script-tag' },
|
||||||
|
openGraph: {
|
||||||
|
title: 'Add Pulse Analytics to Any Website | Pulse by Ciphera',
|
||||||
|
description: 'Add privacy-first analytics to any website with a single script tag.',
|
||||||
|
url: 'https://pulse.ciphera.net/integrations/script-tag',
|
||||||
|
siteName: 'Pulse by Ciphera',
|
||||||
|
type: 'article',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ScriptTagPage() {
|
||||||
|
const jsonLd = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'HowTo',
|
||||||
|
name: 'How to Add Pulse Analytics to Any Website',
|
||||||
|
description: 'Add privacy-first analytics to any website with a single script tag.',
|
||||||
|
step: [
|
||||||
|
{
|
||||||
|
'@type': 'HowToStep',
|
||||||
|
name: 'Copy the script tag',
|
||||||
|
text: 'Copy the Pulse tracking script with your domain.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'@type': 'HowToStep',
|
||||||
|
name: 'Paste into your HTML head',
|
||||||
|
text: 'Add the script tag inside the <head> section of your website.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'@type': 'HowToStep',
|
||||||
|
name: 'Deploy and verify',
|
||||||
|
text: 'Deploy your site and check the Pulse dashboard for incoming data.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tool: {
|
||||||
|
'@type': 'HowToTool',
|
||||||
|
name: 'Pulse by Ciphera',
|
||||||
|
url: 'https://pulse.ciphera.net',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||||
|
/>
|
||||||
|
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
||||||
|
<div className="absolute inset-0 -z-10 pointer-events-none">
|
||||||
|
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
||||||
|
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
||||||
|
<Link
|
||||||
|
href="/integrations"
|
||||||
|
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
||||||
|
>
|
||||||
|
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
||||||
|
Back to Integrations
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-4 mb-8">
|
||||||
|
<div className="p-3 bg-neutral-800 rounded-xl">
|
||||||
|
<svg className="w-10 h-10 text-brand-orange" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h1 className="text-4xl md:text-5xl font-bold text-white">
|
||||||
|
Script Tag Integration
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="prose prose-invert max-w-none">
|
||||||
|
<p className="lead text-xl text-neutral-400">
|
||||||
|
Add Pulse to any website by pasting a single script tag into your HTML.
|
||||||
|
This works with any platform, CMS, or static site.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr className="my-8 border-neutral-800" />
|
||||||
|
|
||||||
|
<h2>Installation</h2>
|
||||||
|
<p>
|
||||||
|
Add the following script tag inside the <code><head></code> section of your website:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<CodeBlock filename="index.html">{`<head>
|
||||||
|
<!-- ... other head elements ... -->
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
data-domain="your-site.com"
|
||||||
|
></script>
|
||||||
|
</head>`}</CodeBlock>
|
||||||
|
|
||||||
|
<h2>Configuration</h2>
|
||||||
|
<ul>
|
||||||
|
<li><code>data-domain</code> — your site's domain as shown in your Pulse dashboard (e.g. <code>example.com</code>), without <code>https://</code></li>
|
||||||
|
<li><code>defer</code> — loads the script without blocking page rendering</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Where to paste the script</h2>
|
||||||
|
<p>
|
||||||
|
Most platforms have a “Custom Code”, “Code Injection”, or “Header Scripts”
|
||||||
|
section in their settings. Look for one of these:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Squarespace:</strong> Settings → Developer Tools → Code Injection → Header</li>
|
||||||
|
<li><strong>Wix:</strong> Settings → Custom Code → Head</li>
|
||||||
|
<li><strong>Webflow:</strong> Project Settings → Custom Code → Head Code</li>
|
||||||
|
<li><strong>Ghost:</strong> Settings → Code Injection → Site Header</li>
|
||||||
|
<li><strong>Any HTML site:</strong> Paste directly into your <code><head></code> tag</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Verify installation</h2>
|
||||||
|
<p>
|
||||||
|
After deploying, visit your site and check the Pulse dashboard. You should
|
||||||
|
see your first page view within a few seconds.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr className="my-8 border-neutral-800" />
|
||||||
|
<h3>Optional: Frustration Tracking</h3>
|
||||||
|
<p>
|
||||||
|
Detect rage clicks and dead clicks by adding the frustration tracking
|
||||||
|
add-on after the core script:
|
||||||
|
</p>
|
||||||
|
<CodeBlock filename="index.html">{`<script defer src="https://pulse.ciphera.net/script.frustration.js"></script>`}</CodeBlock>
|
||||||
|
<p>
|
||||||
|
No extra configuration needed. Add <code>data-no-rage</code> or{' '}
|
||||||
|
<code>data-no-dead</code> to disable individual signals.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
|
||||||
|
|
||||||
export default function VueIntegrationPage() {
|
|
||||||
return (
|
|
||||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
|
||||||
{/* * --- ATMOSPHERE (Background) --- */}
|
|
||||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
|
||||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
|
||||||
<div
|
|
||||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
|
||||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
|
||||||
<Link
|
|
||||||
href="/integrations"
|
|
||||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
|
||||||
>
|
|
||||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
|
||||||
Back to Integrations
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-8">
|
|
||||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
|
||||||
<svg viewBox="0 0 128 128" className="w-10 h-10 text-[#4FC08D] fill-current">
|
|
||||||
<path d="M82.8 24.6h27.8L64 103.4 17.4 24.6h27.8L64 59.4l18.8-34.8z" />
|
|
||||||
<path d="M64 24.6H39L64 67.4l25-42.8H64z" fill="#35495E" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">
|
|
||||||
Vue.js Integration
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="prose prose-invert max-w-none">
|
|
||||||
<p className="lead text-xl text-neutral-400">
|
|
||||||
Integrating Pulse with Vue.js is straightforward. You can add the script to your <code>index.html</code> file.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr className="my-8 border-neutral-800" />
|
|
||||||
|
|
||||||
<h3>Method 1: index.html (Recommended)</h3>
|
|
||||||
<p>
|
|
||||||
Add the script tag to the <code><head></code> section of your <code>index.html</code> file. This works for both Vue 2 and Vue 3 projects created with Vue CLI or Vite.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
|
||||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
|
||||||
<span className="text-xs text-neutral-400 font-mono">index.html</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 overflow-x-auto">
|
|
||||||
<pre className="text-sm font-mono text-neutral-300">
|
|
||||||
{`<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
|
|
||||||
<!-- Pulse Analytics -->
|
|
||||||
<script
|
|
||||||
defer
|
|
||||||
data-domain="your-site.com"
|
|
||||||
src="https://pulse.ciphera.net/script.js"
|
|
||||||
></script>
|
|
||||||
|
|
||||||
<title>My Vue App</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
<script type="module" src="/src/main.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>`}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Method 2: Nuxt.js</h3>
|
|
||||||
<p>
|
|
||||||
For Nuxt.js applications, you should add the script to your <code>nuxt.config.js</code> or <code>nuxt.config.ts</code> file.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
|
||||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
|
||||||
<span className="text-xs text-neutral-400 font-mono">nuxt.config.ts</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 overflow-x-auto">
|
|
||||||
<pre className="text-sm font-mono text-neutral-300">
|
|
||||||
{`export default defineNuxtConfig({
|
|
||||||
app: {
|
|
||||||
head: {
|
|
||||||
script: [
|
|
||||||
{
|
|
||||||
src: 'https://pulse.ciphera.net/script.js',
|
|
||||||
defer: true,
|
|
||||||
'data-domain': 'your-site.com'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})`}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
|
||||||
|
|
||||||
export default function WordPressIntegrationPage() {
|
|
||||||
return (
|
|
||||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
|
||||||
{/* * --- ATMOSPHERE (Background) --- */}
|
|
||||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
|
||||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
|
||||||
<div
|
|
||||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
|
||||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
|
||||||
<Link
|
|
||||||
href="/integrations"
|
|
||||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
|
||||||
>
|
|
||||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
|
||||||
Back to Integrations
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-8">
|
|
||||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
|
||||||
<svg viewBox="0 0 128 128" className="w-10 h-10 text-[#21759B] fill-current">
|
|
||||||
<path d="M116.6 64c0-19.2-10.4-36-26-45.2l28.6 78.4c-1 3.2-2.2 6.2-3.6 9.2-11.4 12.4-27.8 20.2-46 20.2-6.2 0-12.2-.8-17.8-2.4l26.2-76.4c1.2.2 2.4.4 3.6.4 5.4 0 13.8-.8 13.8-.8 2.8-.2 3.2 4 .4 4.2 0 0-2.8.2-6 .4l19 56.6 5.4-18c2.4-7.4 4.2-12.8 4.2-17.4 0-6-2.2-10.2-7.6-12.6-2.8-1.2-2.2-5.4 1.4-5.4h4.4zM64 121.2c-15.8 0-30.2-6.4-40.8-16.8L46.6 36.8c-2.8-.2-5.8-.4-5.8-.4-2.8-.2-2.4-4.4.4-4.2 0 0 8.4.8 13.6.8 5.4 0 13.6-.8 13.6-.8 2.8-.2 3.2 4 .4 4.2 0 0-2.8.2-5.8.4l18.2 54.4 10.6-31.8L64 121.2zM11.4 64c0 17 8.2 32.2 20.8 41.8L18.8 66.8c-.8-3.4-1.2-6.6-1.2-9.2 0-6.8 2.6-13 6.2-17.8C15.6 47.4 11.4 55.2 11.4 64zM64 6.8c16.2 0 30.8 6.8 41.4 17.6-1.4-.2-2.8-.2-4.2-.2-7.8 0-14.2 1.4-14.2 1.4-2.8.6-2.2 4.8.6 4.2 0 0 5-1 10.6-1 2.2 0 4.6.2 6.6.4L88.2 53 71.4 6.8h-7.4z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">
|
|
||||||
WordPress Integration
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="prose prose-invert max-w-none">
|
|
||||||
<p className="lead text-xl text-neutral-400">
|
|
||||||
You can add Pulse to your WordPress site without installing any heavy plugins, or by using a simple code snippet plugin.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr className="my-8 border-neutral-800" />
|
|
||||||
|
|
||||||
<h3>Method 1: Using a Plugin (Easiest)</h3>
|
|
||||||
<ol>
|
|
||||||
<li>Install a plugin like "Insert Headers and Footers" (WPCode).</li>
|
|
||||||
<li>Go to the plugin settings and find the "Scripts in Header" section.</li>
|
|
||||||
<li>Paste the following code snippet:</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
|
||||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
|
||||||
<span className="text-xs text-neutral-400 font-mono">Header Script</span>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 overflow-x-auto">
|
|
||||||
<pre className="text-sm font-mono text-neutral-300">
|
|
||||||
{`<script
|
|
||||||
defer
|
|
||||||
data-domain="your-site.com"
|
|
||||||
src="https://pulse.ciphera.net/script.js"
|
|
||||||
></script>`}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Method 2: Edit Theme Files (Advanced)</h3>
|
|
||||||
<p>
|
|
||||||
If you are comfortable editing your theme files, you can add the script directly to your <code>header.php</code> file.
|
|
||||||
</p>
|
|
||||||
<ol>
|
|
||||||
<li>Go to Appearance > Theme File Editor.</li>
|
|
||||||
<li>Select <code>header.php</code> from the right sidebar.</li>
|
|
||||||
<li>Paste the script tag just before the closing <code></head></code> tag.</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
import type { MetadataRoute } from 'next'
|
import type { MetadataRoute } from 'next'
|
||||||
import { integrations } from '@/lib/integrations'
|
import { integrations } from '@/lib/integrations'
|
||||||
|
import { getIntegrationGuides } from '@/lib/integration-content'
|
||||||
|
|
||||||
const BASE_URL = 'https://pulse.ciphera.net'
|
const BASE_URL = 'https://pulse.ciphera.net'
|
||||||
|
|
||||||
export default function sitemap(): MetadataRoute.Sitemap {
|
export default function sitemap(): MetadataRoute.Sitemap {
|
||||||
|
const guides = getIntegrationGuides()
|
||||||
|
const guidesBySlug = new Map(guides.map((g) => [g.slug, g]))
|
||||||
|
|
||||||
const publicRoutes = [
|
const publicRoutes = [
|
||||||
{ url: '', priority: 1.0, changeFrequency: 'weekly' as const },
|
{ url: '', priority: 1.0, changeFrequency: 'weekly' as const },
|
||||||
{ url: '/about', priority: 0.8, changeFrequency: 'monthly' as const },
|
{ url: '/about', priority: 0.8, changeFrequency: 'monthly' as const },
|
||||||
@@ -13,20 +17,33 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
{ url: '/changelog', priority: 0.6, changeFrequency: 'weekly' as const },
|
{ url: '/changelog', priority: 0.6, changeFrequency: 'weekly' as const },
|
||||||
{ url: '/installation', priority: 0.8, changeFrequency: 'monthly' as const },
|
{ url: '/installation', priority: 0.8, changeFrequency: 'monthly' as const },
|
||||||
{ url: '/integrations', priority: 0.8, changeFrequency: 'monthly' as const },
|
{ url: '/integrations', priority: 0.8, changeFrequency: 'monthly' as const },
|
||||||
|
{ url: '/integrations/script-tag', priority: 0.6, changeFrequency: 'monthly' as const },
|
||||||
]
|
]
|
||||||
|
|
||||||
const integrationRoutes = integrations.map((i) => ({
|
const integrationRoutes = integrations
|
||||||
|
.filter((i) => i.dedicatedPage)
|
||||||
|
.map((i) => {
|
||||||
|
const guide = guidesBySlug.get(i.id)
|
||||||
|
return {
|
||||||
url: `/integrations/${i.id}`,
|
url: `/integrations/${i.id}`,
|
||||||
priority: 0.7,
|
priority: 0.7,
|
||||||
changeFrequency: 'monthly' as const,
|
changeFrequency: 'monthly' as const,
|
||||||
}))
|
lastModified: guide?.date ? new Date(guide.date) : new Date('2026-03-28'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const allRoutes = [...publicRoutes, ...integrationRoutes]
|
return [
|
||||||
|
...publicRoutes.map((route) => ({
|
||||||
return allRoutes.map((route) => ({
|
|
||||||
url: `${BASE_URL}${route.url}`,
|
url: `${BASE_URL}${route.url}`,
|
||||||
lastModified: new Date(),
|
lastModified: new Date('2026-03-28'),
|
||||||
changeFrequency: route.changeFrequency,
|
changeFrequency: route.changeFrequency,
|
||||||
priority: route.priority,
|
priority: route.priority,
|
||||||
}))
|
})),
|
||||||
|
...integrationRoutes.map((route) => ({
|
||||||
|
url: `${BASE_URL}${route.url}`,
|
||||||
|
lastModified: route.lastModified,
|
||||||
|
changeFrequency: route.changeFrequency,
|
||||||
|
priority: route.priority,
|
||||||
|
})),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
39
content/integrations/angular.mdx
Normal file
39
content/integrations/angular.mdx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
title: "Angular"
|
||||||
|
description: "Add Pulse analytics to your Angular application. Simple index.html setup for all Angular versions."
|
||||||
|
category: "framework"
|
||||||
|
brandColor: "#0F0F11"
|
||||||
|
officialUrl: "https://angular.dev"
|
||||||
|
relatedIds: ["react", "vue"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the script to your `src/index.html` — the single entry point for all Angular applications.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add the Pulse script to index.html
|
||||||
|
|
||||||
|
Place the Pulse script inside the `<head>` tag of your Angular app's `src/index.html`.
|
||||||
|
|
||||||
|
<CodeBlock filename="src/index.html">{`<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<title>My Angular App</title>
|
||||||
|
<base href="/">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Angular docs](https://angular.dev/guide/components).
|
||||||
48
content/integrations/astro.mdx
Normal file
48
content/integrations/astro.mdx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
title: "Astro"
|
||||||
|
description: "Integrate Pulse analytics with Astro. Add the script to your base layout for all pages."
|
||||||
|
category: "framework"
|
||||||
|
brandColor: "#BC52EE"
|
||||||
|
officialUrl: "https://docs.astro.build"
|
||||||
|
relatedIds: ["svelte", "hugo", "eleventy"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your base layout so it's included on every page of your Astro site.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add to your base layout
|
||||||
|
|
||||||
|
Place the Pulse script in the `<head>` of your shared layout component.
|
||||||
|
|
||||||
|
<CodeBlock filename="src/layouts/BaseLayout.astro">{`---
|
||||||
|
interface Props {
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const { title } = Astro.props
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<title>{title}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<slot />
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
If you're using Astro's View Transitions, the script will persist across navigations by default since it's in the `<head>`.
|
||||||
|
|
||||||
|
For more details, see the [Astro scripts docs](https://docs.astro.build/en/guides/client-side-scripts/).
|
||||||
42
content/integrations/django.mdx
Normal file
42
content/integrations/django.mdx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
title: "Django"
|
||||||
|
description: "Add Pulse analytics to your Django app. Template-based integration for all Django versions."
|
||||||
|
category: "backend"
|
||||||
|
brandColor: "#092E20"
|
||||||
|
officialUrl: "https://docs.djangoproject.com"
|
||||||
|
relatedIds: ["flask", "laravel", "htmx"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your base template with a debug guard.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add to your base template
|
||||||
|
|
||||||
|
Use Django's template tags to only load the script when `DEBUG` is `False`.
|
||||||
|
|
||||||
|
<CodeBlock filename="templates/base.html">{`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
{% if not debug %}
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<title>{% block title %}My Django App{% endblock %}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
Make sure to pass `debug` to the template context via `settings.DEBUG`, or use a context processor to make it available globally.
|
||||||
|
|
||||||
|
For more details, see the [Django template docs](https://docs.djangoproject.com/en/stable/ref/templates/builtins/).
|
||||||
45
content/integrations/drupal.mdx
Normal file
45
content/integrations/drupal.mdx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
title: "Drupal"
|
||||||
|
description: "Add Pulse analytics to your Drupal site using a module or theme template."
|
||||||
|
category: "cms"
|
||||||
|
brandColor: "#0678BE"
|
||||||
|
officialUrl: "https://www.drupal.org/docs"
|
||||||
|
relatedIds: ["wordpress", "joomla"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script via a contributed module or by editing your theme's Twig template.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: Using Asset Injector module
|
||||||
|
|
||||||
|
Install the [Asset Injector](https://www.drupal.org/project/asset_injector) module and create a new JS injector with the Pulse script. Set it to load on all pages in the header region.
|
||||||
|
|
||||||
|
## Method 2: Edit html.html.twig
|
||||||
|
|
||||||
|
Add the script directly to your theme's `html.html.twig` template in the head area.
|
||||||
|
|
||||||
|
<CodeBlock filename="templates/html.html.twig">{`<!DOCTYPE html>
|
||||||
|
<html{{ html_attributes }}>
|
||||||
|
<head>
|
||||||
|
<head-placeholder token="{{ placeholder_token }}">
|
||||||
|
<title>{{ head_title|safe_join(' | ') }}</title>
|
||||||
|
<css-placeholder token="{{ placeholder_token }}">
|
||||||
|
<js-placeholder token="{{ placeholder_token }}">
|
||||||
|
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
</head>
|
||||||
|
<body{{ attributes }}>
|
||||||
|
{{ page_top }}
|
||||||
|
{{ page }}
|
||||||
|
{{ page_bottom }}
|
||||||
|
<js-bottom-placeholder token="{{ placeholder_token }}">
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Drupal theming docs](https://www.drupal.org/docs/theming-drupal).
|
||||||
38
content/integrations/eleventy.mdx
Normal file
38
content/integrations/eleventy.mdx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
title: "Eleventy"
|
||||||
|
description: "Add Pulse analytics to your Eleventy (11ty) site. Template-based integration."
|
||||||
|
category: "ssg"
|
||||||
|
brandColor: "#222222"
|
||||||
|
officialUrl: "https://www.11ty.dev/docs"
|
||||||
|
relatedIds: ["hugo", "jekyll", "astro"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your base Nunjucks or Liquid layout.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add to your base layout
|
||||||
|
|
||||||
|
Place the Pulse script inside the `<head>` of your shared base template.
|
||||||
|
|
||||||
|
<CodeBlock filename="src/_includes/base.njk">{`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<title>{{ title }}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{ content | safe }}
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Eleventy layouts docs](https://www.11ty.dev/docs/layouts/).
|
||||||
61
content/integrations/express.mdx
Normal file
61
content/integrations/express.mdx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
title: "Express"
|
||||||
|
description: "Serve Pulse analytics from your Express.js app. Middleware or template-based setup."
|
||||||
|
category: "backend"
|
||||||
|
brandColor: "#000000"
|
||||||
|
officialUrl: "https://expressjs.com"
|
||||||
|
relatedIds: ["flask", "nextjs", "react"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your template engine's layout (EJS, Pug, Handlebars) or serve it via static HTML.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: EJS template
|
||||||
|
|
||||||
|
If you use EJS as your template engine, add the script to your layout with a production guard.
|
||||||
|
|
||||||
|
<CodeBlock filename="views/layout.ejs">{`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<% if (process.env.NODE_ENV === 'production') { %>
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<title><%= title %></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- body %>
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: Static HTML
|
||||||
|
|
||||||
|
If you serve static HTML files via Express, add the script directly.
|
||||||
|
|
||||||
|
<CodeBlock filename="public/index.html">{`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<title>My Express App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
40
content/integrations/flask.mdx
Normal file
40
content/integrations/flask.mdx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
title: "Flask"
|
||||||
|
description: "Add Pulse analytics to your Flask app. Jinja2 template integration."
|
||||||
|
category: "backend"
|
||||||
|
brandColor: "#3BABC3"
|
||||||
|
officialUrl: "https://flask.palletsprojects.com"
|
||||||
|
relatedIds: ["django", "htmx", "express"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your Jinja2 base template with a debug guard.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add to your base template
|
||||||
|
|
||||||
|
Use Jinja2's conditional to only load the script when `DEBUG` is off.
|
||||||
|
|
||||||
|
<CodeBlock filename="templates/base.html">{`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
{% if not config.DEBUG %}
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<title>{% block title %}My Flask App{% endblock %}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Flask template docs](https://flask.palletsprojects.com/en/stable/patterns/templateinheritance/).
|
||||||
25
content/integrations/framer.mdx
Normal file
25
content/integrations/framer.mdx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
title: "Framer"
|
||||||
|
description: "Add Pulse analytics to your Framer site via custom code settings."
|
||||||
|
category: "platform"
|
||||||
|
brandColor: "#0055FF"
|
||||||
|
officialUrl: "https://www.framer.com/help"
|
||||||
|
relatedIds: ["webflow", "squarespace", "wix"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your Framer project's custom code settings.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add via Project Settings
|
||||||
|
|
||||||
|
Go to **Project Settings -> General -> Custom Code -> Head** and paste the Pulse script.
|
||||||
|
|
||||||
|
<CodeBlock filename="Project Settings -> Head">{`<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Framer custom code docs](https://www.framer.com/help/articles/custom-code/).
|
||||||
52
content/integrations/gatsby.mdx
Normal file
52
content/integrations/gatsby.mdx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
title: "Gatsby"
|
||||||
|
description: "Add Pulse analytics to your Gatsby site using gatsby-ssr or the Gatsby Head API."
|
||||||
|
category: "ssg"
|
||||||
|
brandColor: "#663399"
|
||||||
|
officialUrl: "https://www.gatsbyjs.com/docs"
|
||||||
|
relatedIds: ["react", "nextjs", "hugo"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Use the Gatsby SSR API or the Gatsby Head API to add Pulse to your site.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: gatsby-ssr.js
|
||||||
|
|
||||||
|
Use the `onRenderBody` hook to inject the Pulse script into every page's `<head>`.
|
||||||
|
|
||||||
|
<CodeBlock filename="gatsby-ssr.js">{`import React from "react"
|
||||||
|
|
||||||
|
export const onRenderBody = ({ setHeadComponents }) => {
|
||||||
|
setHeadComponents([
|
||||||
|
<script
|
||||||
|
key="pulse-analytics"
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
/>,
|
||||||
|
])
|
||||||
|
}`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: Gatsby Head API (v4.19+)
|
||||||
|
|
||||||
|
If you're on Gatsby 4.19 or later, you can use the Head export in any page or template component.
|
||||||
|
|
||||||
|
<CodeBlock filename="src/pages/index.tsx">{`import React from "react"
|
||||||
|
|
||||||
|
export function Head() {
|
||||||
|
return (
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function IndexPage() {
|
||||||
|
return <h1>Hello World</h1>
|
||||||
|
}`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Gatsby Head API docs](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-head/).
|
||||||
27
content/integrations/ghost.mdx
Normal file
27
content/integrations/ghost.mdx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: "Ghost"
|
||||||
|
description: "Add Pulse analytics to your Ghost blog via Code Injection settings."
|
||||||
|
category: "cms"
|
||||||
|
brandColor: "#15171A"
|
||||||
|
officialUrl: "https://ghost.org/docs"
|
||||||
|
relatedIds: ["wordpress", "blogger"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Use Ghost's built-in Code Injection feature to add the Pulse script — no theme editing required.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add via Code Injection
|
||||||
|
|
||||||
|
Go to **Settings -> Code injection -> Site Header** and paste the Pulse script.
|
||||||
|
|
||||||
|
<CodeBlock filename="Settings -> Code injection -> Site Header">{`<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>`}</CodeBlock>
|
||||||
|
|
||||||
|
Alternatively, you can add the script directly to your theme's `default.hbs` template file.
|
||||||
|
|
||||||
|
For more details, see the [Ghost themes docs](https://ghost.org/docs/themes/).
|
||||||
39
content/integrations/gtm.mdx
Normal file
39
content/integrations/gtm.mdx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
title: "Google Tag Manager"
|
||||||
|
description: "Add Pulse analytics via Google Tag Manager. Works with any site using GTM."
|
||||||
|
category: "platform"
|
||||||
|
brandColor: "#246FDB"
|
||||||
|
officialUrl: "https://tagmanager.google.com"
|
||||||
|
relatedIds: ["wordpress", "shopify", "webflow"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add Pulse via Google Tag Manager — works with any site that already has GTM installed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Create a Custom HTML tag
|
||||||
|
|
||||||
|
Follow these steps to add Pulse through GTM:
|
||||||
|
|
||||||
|
1. Go to **Tags -> New -> Custom HTML**
|
||||||
|
2. Paste the snippet below
|
||||||
|
3. Set the trigger to **All Pages**
|
||||||
|
4. Publish your container
|
||||||
|
|
||||||
|
<CodeBlock filename="GTM -> Custom HTML Tag">{`<script defer src="https://pulse.ciphera.net/script.js"></script>`}</CodeBlock>
|
||||||
|
|
||||||
|
That's it. Pulse auto-detects the domain from the page, so no extra configuration is needed.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary className="cursor-pointer text-sm text-neutral-400 hover:text-neutral-700 dark:hover:text-neutral-300">Advanced: override domain or configure options</summary>
|
||||||
|
|
||||||
|
If your site is registered under a different domain than the page hostname, or you need custom options (API endpoint, storage mode, etc.), use `pulseConfig`:
|
||||||
|
|
||||||
|
<CodeBlock filename="GTM -> Custom HTML Tag (with config)">{`<script>
|
||||||
|
window.pulseConfig = { domain: "your-site.com" };
|
||||||
|
</script>
|
||||||
|
<script defer src="https://pulse.ciphera.net/script.js"></script>`}</CodeBlock>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
For more details, see the [GTM Custom HTML tag docs](https://support.google.com/tagmanager/answer/6103696).
|
||||||
44
content/integrations/hugo.mdx
Normal file
44
content/integrations/hugo.mdx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
title: "Hugo"
|
||||||
|
description: "Add Pulse analytics to your Hugo site via a partial or base template."
|
||||||
|
category: "ssg"
|
||||||
|
brandColor: "#FF4088"
|
||||||
|
officialUrl: "https://gohugo.io/documentation"
|
||||||
|
relatedIds: ["jekyll", "eleventy", "astro"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script via a Hugo partial or directly in your base template.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: Create a partial
|
||||||
|
|
||||||
|
Create an analytics partial with a production guard using Hugo's `.Site.IsServer` flag.
|
||||||
|
|
||||||
|
<CodeBlock filename="layouts/partials/analytics.html">{`{{ if not .Site.IsServer }}
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
{{ end }}`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: Include the partial in your base layout
|
||||||
|
|
||||||
|
Add the partial to your `baseof.html` layout.
|
||||||
|
|
||||||
|
<CodeBlock filename="layouts/_default/baseof.html">{`<!DOCTYPE html>
|
||||||
|
<html lang="{{ .Site.Language }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
{{ partial "analytics.html" . }}
|
||||||
|
<title>{{ .Title }}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{ block "main" . }}{{ end }}
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Hugo partials docs](https://gohugo.io/templates/partials/).
|
||||||
41
content/integrations/laravel.mdx
Normal file
41
content/integrations/laravel.mdx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
title: "Laravel"
|
||||||
|
description: "Add Pulse analytics to your Laravel app. Blade template integration for all Laravel versions."
|
||||||
|
category: "backend"
|
||||||
|
brandColor: "#FF2D20"
|
||||||
|
officialUrl: "https://laravel.com/docs"
|
||||||
|
relatedIds: ["django", "rails", "wordpress"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your Blade layout template with a production guard.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add to your Blade layout
|
||||||
|
|
||||||
|
Use Laravel's `@production` directive to only load the script in production.
|
||||||
|
|
||||||
|
<CodeBlock filename="resources/views/layouts/app.blade.php">{`<!DOCTYPE html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
@production
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
@endproduction
|
||||||
|
|
||||||
|
<title>@yield('title')</title>
|
||||||
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
@yield('content')
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Laravel @production docs](https://laravel.com/docs/blade#the-production-directive).
|
||||||
68
content/integrations/nextjs.mdx
Normal file
68
content/integrations/nextjs.mdx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
title: "Next.js"
|
||||||
|
description: "Step-by-step guide to adding Pulse privacy-first analytics to your Next.js app with next/script. Covers App Router and Pages Router."
|
||||||
|
category: "framework"
|
||||||
|
brandColor: "#000000"
|
||||||
|
officialUrl: "https://nextjs.org/docs"
|
||||||
|
relatedIds: ["react", "vercel", "nuxt"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
The best way to add Pulse to your Next.js application is using the built-in `next/script` component.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: App Router
|
||||||
|
|
||||||
|
Add the Pulse script to your root layout so it loads on every page.
|
||||||
|
|
||||||
|
<CodeBlock filename="app/layout.tsx">{`import Script from 'next/script'
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<Script
|
||||||
|
defer
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
data-domain="your-site.com"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: Pages Router
|
||||||
|
|
||||||
|
If you're using the Pages Router, add the script to your custom `_app.tsx`.
|
||||||
|
|
||||||
|
<CodeBlock filename="pages/_app.tsx">{`import Script from 'next/script'
|
||||||
|
import type { AppProps } from 'next/app'
|
||||||
|
|
||||||
|
export default function App({ Component, pageProps }: AppProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Script
|
||||||
|
defer
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
data-domain="your-site.com"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}`}</CodeBlock>
|
||||||
|
|
||||||
|
## Configuration options
|
||||||
|
|
||||||
|
- `data-domain` — your site's domain (without `https://`)
|
||||||
|
- `src` — the Pulse script URL
|
||||||
|
- `strategy="afterInteractive"` — loads the script after the page becomes interactive
|
||||||
|
|
||||||
|
For more details, see the [Next.js Script docs](https://nextjs.org/docs/app/api-reference/components/script).
|
||||||
49
content/integrations/nuxt.mdx
Normal file
49
content/integrations/nuxt.mdx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
title: "Nuxt"
|
||||||
|
description: "Configure Pulse analytics in Nuxt 2 or Nuxt 3 via nuxt.config. Simple, framework-native setup."
|
||||||
|
category: "framework"
|
||||||
|
brandColor: "#00DC82"
|
||||||
|
officialUrl: "https://nuxt.com/docs"
|
||||||
|
relatedIds: ["vue", "nextjs", "vitepress"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Configure Pulse analytics in your `nuxt.config` for a framework-native setup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: Nuxt 3
|
||||||
|
|
||||||
|
Add the Pulse script via the `app.head` option in your Nuxt 3 config.
|
||||||
|
|
||||||
|
<CodeBlock filename="nuxt.config.ts">{`export default defineNuxtConfig({
|
||||||
|
app: {
|
||||||
|
head: {
|
||||||
|
script: [
|
||||||
|
{
|
||||||
|
defer: true,
|
||||||
|
'data-domain': 'your-site.com',
|
||||||
|
src: 'https://pulse.ciphera.net/script.js',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: Nuxt 2
|
||||||
|
|
||||||
|
In Nuxt 2, use the `head` property in your config.
|
||||||
|
|
||||||
|
<CodeBlock filename="nuxt.config.js">{`export default {
|
||||||
|
head: {
|
||||||
|
script: [
|
||||||
|
{
|
||||||
|
defer: true,
|
||||||
|
'data-domain': 'your-site.com',
|
||||||
|
src: 'https://pulse.ciphera.net/script.js',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Nuxt head config docs](https://nuxt.com/docs/api/nuxt-config#head).
|
||||||
42
content/integrations/rails.mdx
Normal file
42
content/integrations/rails.mdx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
title: "Ruby on Rails"
|
||||||
|
description: "Add Pulse analytics to your Ruby on Rails app. ERB layout integration."
|
||||||
|
category: "backend"
|
||||||
|
brandColor: "#D30001"
|
||||||
|
officialUrl: "https://guides.rubyonrails.org"
|
||||||
|
relatedIds: ["laravel", "django", "jekyll"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your application layout with a production environment guard.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add to your application layout
|
||||||
|
|
||||||
|
Use an `if` guard to only load the script in production.
|
||||||
|
|
||||||
|
<CodeBlock filename="app/views/layouts/application.html.erb">{`<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<% if Rails.env.production? %>
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<title><%= yield(:title) || "My Rails App" %></title>
|
||||||
|
<%= csrf_meta_tags %>
|
||||||
|
<%= stylesheet_link_tag "application" %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%= yield %>
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Rails layout docs](https://guides.rubyonrails.org/layouts_and_rendering.html).
|
||||||
56
content/integrations/react.mdx
Normal file
56
content/integrations/react.mdx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
title: "React"
|
||||||
|
description: "Integrate Pulse analytics with any React SPA — Create React App, Vite, or custom setups. Two easy methods."
|
||||||
|
category: "framework"
|
||||||
|
brandColor: "#61DAFB"
|
||||||
|
officialUrl: "https://react.dev"
|
||||||
|
relatedIds: ["nextjs", "remix", "gatsby", "preact"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
For standard React SPAs, add the script to your `index.html`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: index.html (Recommended)
|
||||||
|
|
||||||
|
The simplest approach is to add the Pulse script directly to your HTML entry point.
|
||||||
|
|
||||||
|
<CodeBlock filename="public/index.html">{`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<title>My React App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: Programmatic injection via useEffect
|
||||||
|
|
||||||
|
If you prefer to inject the script programmatically (e.g. only in production), use a `useEffect` hook.
|
||||||
|
|
||||||
|
<CodeBlock filename="src/App.tsx">{`import { useEffect } from 'react'
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
useEffect(() => {
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.defer = true
|
||||||
|
script.setAttribute('data-domain', 'your-site.com')
|
||||||
|
script.src = 'https://pulse.ciphera.net/script.js'
|
||||||
|
document.head.appendChild(script)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <div className="App"><h1>Hello World</h1></div>
|
||||||
|
}`}</CodeBlock>
|
||||||
50
content/integrations/remix.mdx
Normal file
50
content/integrations/remix.mdx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
title: "Remix"
|
||||||
|
description: "Add Pulse analytics to your Remix application via the root route. Simple script tag in app/root.tsx."
|
||||||
|
category: "framework"
|
||||||
|
brandColor: "#000000"
|
||||||
|
officialUrl: "https://remix.run/docs"
|
||||||
|
relatedIds: ["react", "nextjs"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script to your `app/root.tsx` so it's included on every route.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add script to app/root.tsx
|
||||||
|
|
||||||
|
The root route is the top-level layout in Remix. Add the Pulse script inside the `<head>` section.
|
||||||
|
|
||||||
|
<CodeBlock filename="app/root.tsx">{`import {
|
||||||
|
Links,
|
||||||
|
Meta,
|
||||||
|
Outlet,
|
||||||
|
Scripts,
|
||||||
|
ScrollRestoration,
|
||||||
|
} from '@remix-run/react'
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charSet="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<Meta />
|
||||||
|
<Links />
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<Outlet />
|
||||||
|
<ScrollRestoration />
|
||||||
|
<Scripts />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}`}</CodeBlock>
|
||||||
|
|
||||||
|
For more details, see the [Remix root docs](https://remix.run/docs/en/main/file-conventions/root).
|
||||||
45
content/integrations/script-tag.mdx
Normal file
45
content/integrations/script-tag.mdx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
title: "Script Tag"
|
||||||
|
description: "Add privacy-first analytics to any website with a single script tag. Works with any platform, CMS, or framework."
|
||||||
|
category: "platform"
|
||||||
|
brandColor: "#F97316"
|
||||||
|
officialUrl: "https://pulse.ciphera.net"
|
||||||
|
relatedIds: []
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add Pulse to any website by pasting a single script tag into your HTML. This works with any platform, CMS, or static site.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Add the following script tag inside the `<head>` section of your website:
|
||||||
|
|
||||||
|
<CodeBlock filename="index.html">{`<head>
|
||||||
|
<!-- ... other head elements ... -->
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
data-domain="your-site.com"
|
||||||
|
></script>
|
||||||
|
</head>`}</CodeBlock>
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
- `data-domain` — your site's domain as shown in your Pulse dashboard (e.g. `example.com`), without `https://`
|
||||||
|
- `defer` — loads the script without blocking page rendering
|
||||||
|
|
||||||
|
## Where to paste the script
|
||||||
|
|
||||||
|
Most platforms have a "Custom Code", "Code Injection", or "Header Scripts" section in their settings. Look for one of these:
|
||||||
|
|
||||||
|
- **Squarespace:** Settings -> Developer Tools -> Code Injection -> Header
|
||||||
|
- **Wix:** Settings -> Custom Code -> Head
|
||||||
|
- **Webflow:** Project Settings -> Custom Code -> Head Code
|
||||||
|
- **Ghost:** Settings -> Code Injection -> Site Header
|
||||||
|
- **Any HTML site:** Paste directly into your `<head>` tag
|
||||||
|
|
||||||
|
## Verify installation
|
||||||
|
|
||||||
|
After deploying, visit your site and check the Pulse dashboard. You should see your first page view within a few seconds.
|
||||||
32
content/integrations/shopify.mdx
Normal file
32
content/integrations/shopify.mdx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
title: "Shopify"
|
||||||
|
description: "Add Pulse privacy-first analytics to your Shopify store via the theme editor."
|
||||||
|
category: "ecommerce"
|
||||||
|
brandColor: "#7AB55C"
|
||||||
|
officialUrl: "https://shopify.dev/docs"
|
||||||
|
relatedIds: ["woocommerce", "bigcommerce", "prestashop"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script via the Shopify theme editor — no app needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: Edit theme code
|
||||||
|
|
||||||
|
Go to **Online Store -> Themes -> Edit code** and open `layout/theme.liquid`. Add the Pulse script before the closing `</head>` tag.
|
||||||
|
|
||||||
|
<CodeBlock filename="layout/theme.liquid">{`<!-- Add before </head> -->
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: Shopify Plus — Customer Events
|
||||||
|
|
||||||
|
If you're on Shopify Plus, you can add the Pulse script via **Settings -> Customer Events -> Custom Pixels**.
|
||||||
|
|
||||||
|
Use your custom domain or `.myshopify.com` domain as the `data-domain` value.
|
||||||
|
|
||||||
|
For more details, see the [Shopify theme docs](https://shopify.dev/docs/storefronts/themes/architecture/layouts).
|
||||||
27
content/integrations/squarespace.mdx
Normal file
27
content/integrations/squarespace.mdx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: "Squarespace"
|
||||||
|
description: "Add Pulse analytics to your Squarespace site via the Code Injection panel."
|
||||||
|
category: "platform"
|
||||||
|
brandColor: "#000000"
|
||||||
|
officialUrl: "https://support.squarespace.com"
|
||||||
|
relatedIds: ["webflow", "wix", "carrd"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Use Squarespace's Code Injection feature to add the Pulse script.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add via Code Injection
|
||||||
|
|
||||||
|
Go to **Settings -> Developer Tools -> Code Injection -> Header** and paste the Pulse script.
|
||||||
|
|
||||||
|
<CodeBlock filename="Settings -> Code Injection -> Header">{`<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>`}</CodeBlock>
|
||||||
|
|
||||||
|
**Note:** Code Injection requires a Business or Commerce plan.
|
||||||
|
|
||||||
|
For more details, see the [Squarespace code injection docs](https://support.squarespace.com/hc/en-us/articles/205815928).
|
||||||
53
content/integrations/svelte.mdx
Normal file
53
content/integrations/svelte.mdx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
title: "Svelte"
|
||||||
|
description: "Add Pulse analytics to Svelte or SvelteKit. Simple setup for both Vite-based Svelte and SvelteKit applications."
|
||||||
|
category: "framework"
|
||||||
|
brandColor: "#FF3E00"
|
||||||
|
officialUrl: "https://svelte.dev"
|
||||||
|
relatedIds: ["astro", "vue"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the script to your `index.html` for Vite-based Svelte, or use `<svelte:head>` in SvelteKit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: Svelte (Vite)
|
||||||
|
|
||||||
|
For standard Svelte projects using Vite, add the Pulse script to your `index.html`.
|
||||||
|
|
||||||
|
<CodeBlock filename="index.html">{`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<title>My Svelte App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: SvelteKit
|
||||||
|
|
||||||
|
In SvelteKit, use `<svelte:head>` in your root layout to add the script to every page.
|
||||||
|
|
||||||
|
<CodeBlock filename="src/routes/+layout.svelte">{`<svelte:head>
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<slot />`}</CodeBlock>
|
||||||
|
|
||||||
|
Alternatively, you can add the script directly to `src/app.html` in your SvelteKit project.
|
||||||
39
content/integrations/vue.mdx
Normal file
39
content/integrations/vue.mdx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
title: "Vue.js"
|
||||||
|
description: "Add Pulse privacy-first analytics to your Vue.js app. Works with Vue 2, Vue 3, Vue CLI, and Vite."
|
||||||
|
category: "framework"
|
||||||
|
brandColor: "#4FC08D"
|
||||||
|
officialUrl: "https://vuejs.org"
|
||||||
|
relatedIds: ["nuxt", "vitepress"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the script to your `index.html` — works for both Vue CLI and Vite-based projects.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add the Pulse script to index.html
|
||||||
|
|
||||||
|
Both Vue CLI and Vite use an `index.html` as the entry point. Simply add the Pulse script inside the `<head>` tag.
|
||||||
|
|
||||||
|
<CodeBlock filename="index.html">{`<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<title>My Vue App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>`}</CodeBlock>
|
||||||
|
|
||||||
|
Looking for Nuxt? Check the dedicated [Nuxt guide](/integrations/nuxt).
|
||||||
27
content/integrations/webflow.mdx
Normal file
27
content/integrations/webflow.mdx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: "Webflow"
|
||||||
|
description: "Add Pulse analytics to your Webflow site via project custom code settings."
|
||||||
|
category: "platform"
|
||||||
|
brandColor: "#146EF5"
|
||||||
|
officialUrl: "https://university.webflow.com"
|
||||||
|
relatedIds: ["squarespace", "wix", "framer"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Paste the Pulse script into your Webflow project's custom code settings.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add via Project Settings
|
||||||
|
|
||||||
|
Go to **Project Settings -> Custom Code -> Head Code** and paste the Pulse script.
|
||||||
|
|
||||||
|
<CodeBlock filename="Project Settings -> Head Code">{`<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>`}</CodeBlock>
|
||||||
|
|
||||||
|
**Note:** Custom code requires a paid Webflow site plan. The script won't appear in the Designer preview — publish your site to see it in action.
|
||||||
|
|
||||||
|
For more details, see the [Webflow custom code docs](https://university.webflow.com/lesson/custom-code-in-the-head-and-body-tag).
|
||||||
27
content/integrations/wix.mdx
Normal file
27
content/integrations/wix.mdx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: "Wix"
|
||||||
|
description: "Add Pulse analytics to your Wix site via Custom Code settings."
|
||||||
|
category: "platform"
|
||||||
|
brandColor: "#0C6EFC"
|
||||||
|
officialUrl: "https://support.wix.com"
|
||||||
|
relatedIds: ["webflow", "squarespace", "framer"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Use Wix's Custom Code settings to add the Pulse script.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add via Custom Code
|
||||||
|
|
||||||
|
Go to **Settings -> Custom Code -> Add Custom Code**. Set the placement to **Head** and apply it to **All pages**.
|
||||||
|
|
||||||
|
<CodeBlock filename="Custom Code Snippet">{`<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>`}</CodeBlock>
|
||||||
|
|
||||||
|
**Note:** Custom Code requires a Wix Premium plan.
|
||||||
|
|
||||||
|
For more details, see the [Wix custom code docs](https://support.wix.com/en/article/embedding-custom-code-on-your-site).
|
||||||
27
content/integrations/wordpress.mdx
Normal file
27
content/integrations/wordpress.mdx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: "WordPress"
|
||||||
|
description: "Add Pulse analytics to your WordPress site via a plugin or theme header code."
|
||||||
|
category: "cms"
|
||||||
|
brandColor: "#21759B"
|
||||||
|
officialUrl: "https://wordpress.org/documentation"
|
||||||
|
relatedIds: ["ghost", "drupal", "woocommerce"]
|
||||||
|
date: "2026-03-28"
|
||||||
|
---
|
||||||
|
|
||||||
|
Add the Pulse script via a plugin or by editing your theme's header file directly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1: Using a plugin (Recommended)
|
||||||
|
|
||||||
|
The easiest way is to use the [WPCode (Insert Headers and Footers)](https://wordpress.org/plugins/insert-headers-and-footers/) plugin. Install it, then go to **Code Snippets -> Header & Footer** and paste the Pulse script into the Header section.
|
||||||
|
|
||||||
|
<CodeBlock filename="Header Script">{`<script
|
||||||
|
defer
|
||||||
|
data-domain="your-site.com"
|
||||||
|
src="https://pulse.ciphera.net/script.js"
|
||||||
|
></script>`}</CodeBlock>
|
||||||
|
|
||||||
|
## Method 2: Edit header.php directly
|
||||||
|
|
||||||
|
Go to **Appearance -> Theme File Editor** and edit `header.php`. Add the Pulse script before the closing `</head>` tag.
|
||||||
63
lib/integration-content.ts
Normal file
63
lib/integration-content.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
import matter from 'gray-matter'
|
||||||
|
|
||||||
|
const CONTENT_DIR = path.join(process.cwd(), 'content', 'integrations')
|
||||||
|
|
||||||
|
export interface IntegrationGuideMeta {
|
||||||
|
slug: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
category: string
|
||||||
|
brandColor: string
|
||||||
|
officialUrl: string
|
||||||
|
relatedIds: string[]
|
||||||
|
date: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IntegrationGuideArticle extends IntegrationGuideMeta {
|
||||||
|
content: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIntegrationGuides(): IntegrationGuideMeta[] {
|
||||||
|
if (!fs.existsSync(CONTENT_DIR)) return []
|
||||||
|
|
||||||
|
const files = fs.readdirSync(CONTENT_DIR).filter((f) => f.endsWith('.mdx'))
|
||||||
|
|
||||||
|
return files.map((filename) => {
|
||||||
|
const slug = filename.replace(/\.mdx$/, '')
|
||||||
|
const raw = fs.readFileSync(path.join(CONTENT_DIR, filename), 'utf-8')
|
||||||
|
const { data } = matter(raw)
|
||||||
|
|
||||||
|
return {
|
||||||
|
slug,
|
||||||
|
title: data.title,
|
||||||
|
description: data.description,
|
||||||
|
category: data.category,
|
||||||
|
brandColor: data.brandColor,
|
||||||
|
officialUrl: data.officialUrl,
|
||||||
|
relatedIds: data.relatedIds || [],
|
||||||
|
date: data.date,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIntegrationGuide(slug: string): IntegrationGuideArticle | null {
|
||||||
|
const filePath = path.join(CONTENT_DIR, `${slug}.mdx`)
|
||||||
|
if (!fs.existsSync(filePath)) return null
|
||||||
|
|
||||||
|
const raw = fs.readFileSync(filePath, 'utf-8')
|
||||||
|
const { data, content } = matter(raw)
|
||||||
|
|
||||||
|
return {
|
||||||
|
slug,
|
||||||
|
title: data.title,
|
||||||
|
description: data.description,
|
||||||
|
category: data.category,
|
||||||
|
brandColor: data.brandColor,
|
||||||
|
officialUrl: data.officialUrl,
|
||||||
|
relatedIds: data.relatedIds || [],
|
||||||
|
date: data.date,
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -34,10 +34,10 @@ export interface Integration {
|
|||||||
icon: ReactNode
|
icon: ReactNode
|
||||||
/** URL to official documentation / website */
|
/** URL to official documentation / website */
|
||||||
officialUrl: string
|
officialUrl: string
|
||||||
/** SEO meta description for this integration's guide page */
|
|
||||||
seoDescription: string
|
|
||||||
/** Related integration IDs for cross-linking */
|
/** Related integration IDs for cross-linking */
|
||||||
relatedIds: string[]
|
relatedIds: string[]
|
||||||
|
/** Whether this integration has a dedicated guide page */
|
||||||
|
dedicatedPage: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// * ─── Category labels (for UI grouping) ──────────────────────────────────────
|
// * ─── Category labels (for UI grouping) ──────────────────────────────────────
|
||||||
@@ -79,9 +79,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://nextjs.org/docs',
|
officialUrl: 'https://nextjs.org/docs',
|
||||||
seoDescription:
|
|
||||||
'Step-by-step guide to adding Pulse privacy-first analytics to your Next.js app with next/script. Covers App Router and Pages Router.',
|
|
||||||
relatedIds: ['react', 'vercel', 'nuxt'],
|
relatedIds: ['react', 'vercel', 'nuxt'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'react',
|
id: 'react',
|
||||||
@@ -95,9 +94,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://react.dev',
|
officialUrl: 'https://react.dev',
|
||||||
seoDescription:
|
|
||||||
'Integrate Pulse analytics with any React SPA — Create React App, Vite, or custom setups. Two easy methods.',
|
|
||||||
relatedIds: ['nextjs', 'remix', 'gatsby', 'preact'],
|
relatedIds: ['nextjs', 'remix', 'gatsby', 'preact'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'vue',
|
id: 'vue',
|
||||||
@@ -111,9 +109,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://vuejs.org',
|
officialUrl: 'https://vuejs.org',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse privacy-first analytics to your Vue.js app. Works with Vue 2, Vue 3, Vue CLI, and Vite.',
|
|
||||||
relatedIds: ['nuxt', 'vitepress'],
|
relatedIds: ['nuxt', 'vitepress'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'angular',
|
id: 'angular',
|
||||||
@@ -128,9 +125,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://angular.dev',
|
officialUrl: 'https://angular.dev',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Angular application. Simple index.html setup for all Angular versions.',
|
|
||||||
relatedIds: ['react', 'vue'],
|
relatedIds: ['react', 'vue'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'svelte',
|
id: 'svelte',
|
||||||
@@ -144,9 +140,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://svelte.dev',
|
officialUrl: 'https://svelte.dev',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to Svelte or SvelteKit. Simple setup for both Vite-based Svelte and SvelteKit applications.',
|
|
||||||
relatedIds: ['astro', 'vue'],
|
relatedIds: ['astro', 'vue'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'nuxt',
|
id: 'nuxt',
|
||||||
@@ -160,9 +155,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://nuxt.com/docs',
|
officialUrl: 'https://nuxt.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Configure Pulse analytics in Nuxt 2 or Nuxt 3 via nuxt.config. Simple, framework-native setup.',
|
|
||||||
relatedIds: ['vue', 'nextjs', 'vitepress'],
|
relatedIds: ['vue', 'nextjs', 'vitepress'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'remix',
|
id: 'remix',
|
||||||
@@ -177,9 +171,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://remix.run/docs',
|
officialUrl: 'https://remix.run/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Remix application via the root route. Simple script tag in app/root.tsx.',
|
|
||||||
relatedIds: ['react', 'nextjs'],
|
relatedIds: ['react', 'nextjs'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'astro',
|
id: 'astro',
|
||||||
@@ -193,9 +186,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.astro.build',
|
officialUrl: 'https://docs.astro.build',
|
||||||
seoDescription:
|
|
||||||
'Integrate Pulse analytics with Astro. Add the script to your base layout for all pages.',
|
|
||||||
relatedIds: ['svelte', 'hugo', 'eleventy'],
|
relatedIds: ['svelte', 'hugo', 'eleventy'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'solidjs',
|
id: 'solidjs',
|
||||||
@@ -209,9 +201,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.solidjs.com/docs',
|
officialUrl: 'https://www.solidjs.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Solid.js application. Simple index.html script tag setup.',
|
|
||||||
relatedIds: ['react', 'qwik', 'preact'],
|
relatedIds: ['react', 'qwik', 'preact'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'qwik',
|
id: 'qwik',
|
||||||
@@ -225,9 +216,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://qwik.dev/docs',
|
officialUrl: 'https://qwik.dev/docs',
|
||||||
seoDescription:
|
|
||||||
'Integrate Pulse analytics with Qwik. Add the script to your root entry file.',
|
|
||||||
relatedIds: ['react', 'solidjs', 'astro'],
|
relatedIds: ['react', 'solidjs', 'astro'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'preact',
|
id: 'preact',
|
||||||
@@ -241,9 +231,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://preactjs.com/guide',
|
officialUrl: 'https://preactjs.com/guide',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Preact application. Same simple setup as any Vite or HTML project.',
|
|
||||||
relatedIds: ['react', 'solidjs'],
|
relatedIds: ['react', 'solidjs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'htmx',
|
id: 'htmx',
|
||||||
@@ -257,9 +246,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://htmx.org/docs',
|
officialUrl: 'https://htmx.org/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your HTMX-powered site. Works with any backend serving HTML.',
|
|
||||||
relatedIds: ['django', 'flask', 'laravel', 'rails'],
|
relatedIds: ['django', 'flask', 'laravel', 'rails'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ember',
|
id: 'ember',
|
||||||
@@ -273,9 +261,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://guides.emberjs.com',
|
officialUrl: 'https://guides.emberjs.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Ember.js app. Simple index.html script tag setup.',
|
|
||||||
relatedIds: ['react', 'angular'],
|
relatedIds: ['react', 'angular'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── Backend Frameworks ───────────────────────────────────────────────────
|
// * ─── Backend Frameworks ───────────────────────────────────────────────────
|
||||||
@@ -291,9 +278,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://laravel.com/docs',
|
officialUrl: 'https://laravel.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Laravel app. Blade template integration for all Laravel versions.',
|
|
||||||
relatedIds: ['django', 'rails', 'wordpress'],
|
relatedIds: ['django', 'rails', 'wordpress'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'django',
|
id: 'django',
|
||||||
@@ -307,9 +293,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.djangoproject.com',
|
officialUrl: 'https://docs.djangoproject.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Django app. Template-based integration for all Django versions.',
|
|
||||||
relatedIds: ['flask', 'laravel', 'htmx'],
|
relatedIds: ['flask', 'laravel', 'htmx'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'rails',
|
id: 'rails',
|
||||||
@@ -323,9 +308,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://guides.rubyonrails.org',
|
officialUrl: 'https://guides.rubyonrails.org',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Ruby on Rails app. ERB layout integration.',
|
|
||||||
relatedIds: ['laravel', 'django', 'jekyll'],
|
relatedIds: ['laravel', 'django', 'jekyll'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'flask',
|
id: 'flask',
|
||||||
@@ -339,9 +323,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://flask.palletsprojects.com',
|
officialUrl: 'https://flask.palletsprojects.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Flask app. Jinja2 template integration.',
|
|
||||||
relatedIds: ['django', 'htmx', 'express'],
|
relatedIds: ['django', 'htmx', 'express'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'express',
|
id: 'express',
|
||||||
@@ -356,9 +339,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://expressjs.com',
|
officialUrl: 'https://expressjs.com',
|
||||||
seoDescription:
|
|
||||||
'Serve Pulse analytics from your Express.js app. Middleware or template-based setup.',
|
|
||||||
relatedIds: ['flask', 'nextjs', 'react'],
|
relatedIds: ['flask', 'nextjs', 'react'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── Static Sites & Documentation ─────────────────────────────────────────
|
// * ─── Static Sites & Documentation ─────────────────────────────────────────
|
||||||
@@ -374,9 +356,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.gatsbyjs.com/docs',
|
officialUrl: 'https://www.gatsbyjs.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Gatsby site using gatsby-ssr or the Gatsby Head API.',
|
|
||||||
relatedIds: ['react', 'nextjs', 'hugo'],
|
relatedIds: ['react', 'nextjs', 'hugo'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'hugo',
|
id: 'hugo',
|
||||||
@@ -390,9 +371,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://gohugo.io/documentation',
|
officialUrl: 'https://gohugo.io/documentation',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Hugo site via a partial or base template.',
|
|
||||||
relatedIds: ['jekyll', 'eleventy', 'astro'],
|
relatedIds: ['jekyll', 'eleventy', 'astro'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'eleventy',
|
id: 'eleventy',
|
||||||
@@ -407,9 +387,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.11ty.dev/docs',
|
officialUrl: 'https://www.11ty.dev/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Eleventy (11ty) site. Template-based integration.',
|
|
||||||
relatedIds: ['hugo', 'jekyll', 'astro'],
|
relatedIds: ['hugo', 'jekyll', 'astro'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'jekyll',
|
id: 'jekyll',
|
||||||
@@ -423,9 +402,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://jekyllrb.com/docs',
|
officialUrl: 'https://jekyllrb.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Jekyll site. Liquid template integration for GitHub Pages and beyond.',
|
|
||||||
relatedIds: ['hugo', 'eleventy', 'github-pages'],
|
relatedIds: ['hugo', 'eleventy', 'github-pages'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'docusaurus',
|
id: 'docusaurus',
|
||||||
@@ -439,9 +417,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docusaurus.io/docs',
|
officialUrl: 'https://docusaurus.io/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Docusaurus documentation site via docusaurus.config.js.',
|
|
||||||
relatedIds: ['vitepress', 'mkdocs', 'gatsby'],
|
relatedIds: ['vitepress', 'mkdocs', 'gatsby'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'vitepress',
|
id: 'vitepress',
|
||||||
@@ -455,9 +432,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://vitepress.dev',
|
officialUrl: 'https://vitepress.dev',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your VitePress documentation site via config.',
|
|
||||||
relatedIds: ['docusaurus', 'vue', 'nuxt'],
|
relatedIds: ['docusaurus', 'vue', 'nuxt'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'hexo',
|
id: 'hexo',
|
||||||
@@ -471,9 +447,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://hexo.io/docs',
|
officialUrl: 'https://hexo.io/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Hexo blog or documentation site.',
|
|
||||||
relatedIds: ['hugo', 'jekyll', 'eleventy'],
|
relatedIds: ['hugo', 'jekyll', 'eleventy'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'mkdocs',
|
id: 'mkdocs',
|
||||||
@@ -487,9 +462,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.mkdocs.org',
|
officialUrl: 'https://www.mkdocs.org',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your MkDocs documentation site.',
|
|
||||||
relatedIds: ['docusaurus', 'vitepress', 'django'],
|
relatedIds: ['docusaurus', 'vitepress', 'django'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── CMS & Blogging ──────────────────────────────────────────────────────
|
// * ─── CMS & Blogging ──────────────────────────────────────────────────────
|
||||||
@@ -505,9 +479,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://wordpress.org/documentation',
|
officialUrl: 'https://wordpress.org/documentation',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your WordPress site via a plugin or theme header code.',
|
|
||||||
relatedIds: ['ghost', 'drupal', 'woocommerce'],
|
relatedIds: ['ghost', 'drupal', 'woocommerce'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ghost',
|
id: 'ghost',
|
||||||
@@ -522,9 +495,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://ghost.org/docs',
|
officialUrl: 'https://ghost.org/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Ghost blog via Code Injection settings.',
|
|
||||||
relatedIds: ['wordpress', 'blogger'],
|
relatedIds: ['wordpress', 'blogger'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'drupal',
|
id: 'drupal',
|
||||||
@@ -538,9 +510,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.drupal.org/docs',
|
officialUrl: 'https://www.drupal.org/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Drupal site using a module or theme template.',
|
|
||||||
relatedIds: ['wordpress', 'joomla'],
|
relatedIds: ['wordpress', 'joomla'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'joomla',
|
id: 'joomla',
|
||||||
@@ -554,9 +525,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.joomla.org',
|
officialUrl: 'https://docs.joomla.org',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Joomla site via template or extension.',
|
|
||||||
relatedIds: ['wordpress', 'drupal'],
|
relatedIds: ['wordpress', 'drupal'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'strapi',
|
id: 'strapi',
|
||||||
@@ -570,9 +540,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.strapi.io',
|
officialUrl: 'https://docs.strapi.io',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Strapi-powered frontend.',
|
|
||||||
relatedIds: ['contentful', 'sanity', 'nextjs'],
|
relatedIds: ['contentful', 'sanity', 'nextjs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'sanity',
|
id: 'sanity',
|
||||||
@@ -587,9 +556,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.sanity.io/docs',
|
officialUrl: 'https://www.sanity.io/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Sanity-powered frontend application.',
|
|
||||||
relatedIds: ['strapi', 'contentful', 'nextjs'],
|
relatedIds: ['strapi', 'contentful', 'nextjs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'contentful',
|
id: 'contentful',
|
||||||
@@ -603,9 +571,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.contentful.com/developers/docs',
|
officialUrl: 'https://www.contentful.com/developers/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Contentful-powered frontend.',
|
|
||||||
relatedIds: ['strapi', 'sanity', 'nextjs'],
|
relatedIds: ['strapi', 'sanity', 'nextjs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'payload',
|
id: 'payload',
|
||||||
@@ -620,9 +587,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://payloadcms.com/docs',
|
officialUrl: 'https://payloadcms.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Payload CMS frontend application.',
|
|
||||||
relatedIds: ['strapi', 'contentful', 'nextjs'],
|
relatedIds: ['strapi', 'contentful', 'nextjs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── eCommerce ────────────────────────────────────────────────────────────
|
// * ─── eCommerce ────────────────────────────────────────────────────────────
|
||||||
@@ -638,9 +604,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://shopify.dev/docs',
|
officialUrl: 'https://shopify.dev/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse privacy-first analytics to your Shopify store via the theme editor.',
|
|
||||||
relatedIds: ['woocommerce', 'bigcommerce', 'prestashop'],
|
relatedIds: ['woocommerce', 'bigcommerce', 'prestashop'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'woocommerce',
|
id: 'woocommerce',
|
||||||
@@ -654,9 +619,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://woocommerce.com/documentation',
|
officialUrl: 'https://woocommerce.com/documentation',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your WooCommerce store. WordPress-based setup.',
|
|
||||||
relatedIds: ['shopify', 'wordpress', 'bigcommerce'],
|
relatedIds: ['shopify', 'wordpress', 'bigcommerce'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bigcommerce',
|
id: 'bigcommerce',
|
||||||
@@ -671,9 +635,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://developer.bigcommerce.com/docs',
|
officialUrl: 'https://developer.bigcommerce.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your BigCommerce store via Script Manager.',
|
|
||||||
relatedIds: ['shopify', 'woocommerce', 'prestashop'],
|
relatedIds: ['shopify', 'woocommerce', 'prestashop'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'prestashop',
|
id: 'prestashop',
|
||||||
@@ -687,9 +650,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://devdocs.prestashop-project.org',
|
officialUrl: 'https://devdocs.prestashop-project.org',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your PrestaShop store via theme template.',
|
|
||||||
relatedIds: ['shopify', 'woocommerce', 'bigcommerce'],
|
relatedIds: ['shopify', 'woocommerce', 'bigcommerce'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── Platforms & Tools ────────────────────────────────────────────────────
|
// * ─── Platforms & Tools ────────────────────────────────────────────────────
|
||||||
@@ -705,9 +667,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://university.webflow.com',
|
officialUrl: 'https://university.webflow.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Webflow site via project custom code settings.',
|
|
||||||
relatedIds: ['squarespace', 'wix', 'framer'],
|
relatedIds: ['squarespace', 'wix', 'framer'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'squarespace',
|
id: 'squarespace',
|
||||||
@@ -722,9 +683,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://support.squarespace.com',
|
officialUrl: 'https://support.squarespace.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Squarespace site via the Code Injection panel.',
|
|
||||||
relatedIds: ['webflow', 'wix', 'carrd'],
|
relatedIds: ['webflow', 'wix', 'carrd'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'wix',
|
id: 'wix',
|
||||||
@@ -738,9 +698,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://support.wix.com',
|
officialUrl: 'https://support.wix.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Wix site via Custom Code settings.',
|
|
||||||
relatedIds: ['webflow', 'squarespace', 'framer'],
|
relatedIds: ['webflow', 'squarespace', 'framer'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'framer',
|
id: 'framer',
|
||||||
@@ -754,9 +713,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.framer.com/help',
|
officialUrl: 'https://www.framer.com/help',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Framer site via custom code settings.',
|
|
||||||
relatedIds: ['webflow', 'squarespace', 'wix'],
|
relatedIds: ['webflow', 'squarespace', 'wix'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'carrd',
|
id: 'carrd',
|
||||||
@@ -770,9 +728,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://carrd.co/docs',
|
officialUrl: 'https://carrd.co/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Carrd one-page site via head code.',
|
|
||||||
relatedIds: ['framer', 'webflow'],
|
relatedIds: ['framer', 'webflow'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'blogger',
|
id: 'blogger',
|
||||||
@@ -786,9 +743,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://support.google.com/blogger',
|
officialUrl: 'https://support.google.com/blogger',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Blogger blog via theme HTML editor.',
|
|
||||||
relatedIds: ['wordpress', 'ghost'],
|
relatedIds: ['wordpress', 'ghost'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gtm',
|
id: 'gtm',
|
||||||
@@ -802,9 +758,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://tagmanager.google.com',
|
officialUrl: 'https://tagmanager.google.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics via Google Tag Manager. Works with any site using GTM.',
|
|
||||||
relatedIds: ['wordpress', 'shopify', 'webflow'],
|
relatedIds: ['wordpress', 'shopify', 'webflow'],
|
||||||
|
dedicatedPage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'notion',
|
id: 'notion',
|
||||||
@@ -819,9 +774,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.notion.so',
|
officialUrl: 'https://www.notion.so',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to Notion-powered websites using Super.so, Potion, or similar tools.',
|
|
||||||
relatedIds: ['webflow', 'framer', 'carrd'],
|
relatedIds: ['webflow', 'framer', 'carrd'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── Hosting & Deployment ─────────────────────────────────────────────────
|
// * ─── Hosting & Deployment ─────────────────────────────────────────────────
|
||||||
@@ -837,9 +791,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://developers.cloudflare.com/pages',
|
officialUrl: 'https://developers.cloudflare.com/pages',
|
||||||
seoDescription:
|
|
||||||
'Deploy with Pulse analytics on Cloudflare Pages. Works with any framework.',
|
|
||||||
relatedIds: ['netlify', 'vercel', 'github-pages'],
|
relatedIds: ['netlify', 'vercel', 'github-pages'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'netlify',
|
id: 'netlify',
|
||||||
@@ -853,9 +806,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.netlify.com',
|
officialUrl: 'https://docs.netlify.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to sites deployed on Netlify. Snippet injection and build-based methods.',
|
|
||||||
relatedIds: ['cloudflare-pages', 'vercel', 'github-pages'],
|
relatedIds: ['cloudflare-pages', 'vercel', 'github-pages'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'vercel',
|
id: 'vercel',
|
||||||
@@ -870,9 +822,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://vercel.com/docs',
|
officialUrl: 'https://vercel.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to sites deployed on Vercel. Works with any framework.',
|
|
||||||
relatedIds: ['netlify', 'cloudflare-pages', 'nextjs'],
|
relatedIds: ['netlify', 'cloudflare-pages', 'nextjs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'github-pages',
|
id: 'github-pages',
|
||||||
@@ -887,9 +838,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.github.com/en/pages',
|
officialUrl: 'https://docs.github.com/en/pages',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your GitHub Pages site. Works with Jekyll, Hugo, or plain HTML.',
|
|
||||||
relatedIds: ['jekyll', 'hugo', 'netlify'],
|
relatedIds: ['jekyll', 'hugo', 'netlify'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── CMS & Blogging (continued) ──────────────────────────────────────────
|
// * ─── CMS & Blogging (continued) ──────────────────────────────────────────
|
||||||
@@ -905,9 +855,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://craftcms.com/docs',
|
officialUrl: 'https://craftcms.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Craft CMS site via Twig templates. Simple installation.',
|
|
||||||
relatedIds: ['wordpress', 'statamic', 'drupal'],
|
relatedIds: ['wordpress', 'statamic', 'drupal'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'statamic',
|
id: 'statamic',
|
||||||
@@ -921,9 +870,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://statamic.dev/docs',
|
officialUrl: 'https://statamic.dev/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Statamic site. Antlers template integration.',
|
|
||||||
relatedIds: ['craftcms', 'laravel', 'wordpress'],
|
relatedIds: ['craftcms', 'laravel', 'wordpress'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'typo3',
|
id: 'typo3',
|
||||||
@@ -937,9 +885,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.typo3.org',
|
officialUrl: 'https://docs.typo3.org',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your TYPO3 CMS site. TypoScript and Fluid template integration.',
|
|
||||||
relatedIds: ['wordpress', 'drupal', 'joomla'],
|
relatedIds: ['wordpress', 'drupal', 'joomla'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'kirby',
|
id: 'kirby',
|
||||||
@@ -954,9 +901,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://getkirby.com/docs',
|
officialUrl: 'https://getkirby.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Kirby CMS site. Simple PHP snippet integration.',
|
|
||||||
relatedIds: ['craftcms', 'statamic', 'grav'],
|
relatedIds: ['craftcms', 'statamic', 'grav'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'grav',
|
id: 'grav',
|
||||||
@@ -971,9 +917,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://learn.getgrav.org',
|
officialUrl: 'https://learn.getgrav.org',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Grav flat-file CMS. Twig template integration.',
|
|
||||||
relatedIds: ['kirby', 'craftcms', 'hugo'],
|
relatedIds: ['kirby', 'craftcms', 'hugo'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'umbraco',
|
id: 'umbraco',
|
||||||
@@ -987,9 +932,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.umbraco.com',
|
officialUrl: 'https://docs.umbraco.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Umbraco CMS site. Razor view integration for .NET.',
|
|
||||||
relatedIds: ['wordpress', 'drupal', 'typo3'],
|
relatedIds: ['wordpress', 'drupal', 'typo3'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'storyblok',
|
id: 'storyblok',
|
||||||
@@ -1003,9 +947,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.storyblok.com/docs',
|
officialUrl: 'https://www.storyblok.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Storyblok-powered frontend application.',
|
|
||||||
relatedIds: ['contentful', 'prismic', 'nextjs'],
|
relatedIds: ['contentful', 'prismic', 'nextjs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'prismic',
|
id: 'prismic',
|
||||||
@@ -1019,9 +962,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://prismic.io/docs',
|
officialUrl: 'https://prismic.io/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Prismic-powered frontend application.',
|
|
||||||
relatedIds: ['contentful', 'storyblok', 'nextjs'],
|
relatedIds: ['contentful', 'storyblok', 'nextjs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── eCommerce (continued) ───────────────────────────────────────────────
|
// * ─── eCommerce (continued) ───────────────────────────────────────────────
|
||||||
@@ -1037,9 +979,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://developer.shopware.com/docs',
|
officialUrl: 'https://developer.shopware.com/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Shopware 6 store via theme template.',
|
|
||||||
relatedIds: ['shopify', 'woocommerce', 'magento'],
|
relatedIds: ['shopify', 'woocommerce', 'magento'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'magento',
|
id: 'magento',
|
||||||
@@ -1053,9 +994,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://developer.adobe.com/commerce',
|
officialUrl: 'https://developer.adobe.com/commerce',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Magento or Adobe Commerce store via layout XML.',
|
|
||||||
relatedIds: ['shopify', 'woocommerce', 'shopware'],
|
relatedIds: ['shopify', 'woocommerce', 'shopware'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── Platforms & Tools (continued) ───────────────────────────────────────
|
// * ─── Platforms & Tools (continued) ───────────────────────────────────────
|
||||||
@@ -1072,9 +1012,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://manual.bubble.io',
|
officialUrl: 'https://manual.bubble.io',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Bubble no-code app via the SEO/Meta tags section.',
|
|
||||||
relatedIds: ['webflow', 'framer', 'wix'],
|
relatedIds: ['webflow', 'framer', 'wix'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'discourse',
|
id: 'discourse',
|
||||||
@@ -1089,9 +1028,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://meta.discourse.org/docs',
|
officialUrl: 'https://meta.discourse.org/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Discourse forum via admin customization.',
|
|
||||||
relatedIds: ['wordpress', 'ghost'],
|
relatedIds: ['wordpress', 'ghost'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'hubspot',
|
id: 'hubspot',
|
||||||
@@ -1105,9 +1043,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://knowledge.hubspot.com',
|
officialUrl: 'https://knowledge.hubspot.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to HubSpot landing pages and website via Settings.',
|
|
||||||
relatedIds: ['wordpress', 'webflow'],
|
relatedIds: ['wordpress', 'webflow'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'substack',
|
id: 'substack',
|
||||||
@@ -1121,9 +1058,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://substack.com',
|
officialUrl: 'https://substack.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Substack publication using custom domain settings.',
|
|
||||||
relatedIds: ['ghost', 'blogger', 'wordpress'],
|
relatedIds: ['ghost', 'blogger', 'wordpress'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'linktree',
|
id: 'linktree',
|
||||||
@@ -1137,9 +1073,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://linktr.ee',
|
officialUrl: 'https://linktr.ee',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Linktree link-in-bio page.',
|
|
||||||
relatedIds: ['carrd', 'framer', 'webflow'],
|
relatedIds: ['carrd', 'framer', 'webflow'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'weebly',
|
id: 'weebly',
|
||||||
@@ -1153,9 +1088,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.weebly.com',
|
officialUrl: 'https://www.weebly.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Weebly website via the header code settings.',
|
|
||||||
relatedIds: ['squarespace', 'wix', 'webflow'],
|
relatedIds: ['squarespace', 'wix', 'webflow'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── Static Sites & Documentation (continued) ───────────────────────────
|
// * ─── Static Sites & Documentation (continued) ───────────────────────────
|
||||||
@@ -1171,9 +1105,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.gitbook.com',
|
officialUrl: 'https://docs.gitbook.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your GitBook-hosted documentation.',
|
|
||||||
relatedIds: ['docusaurus', 'readme', 'readthedocs'],
|
relatedIds: ['docusaurus', 'readme', 'readthedocs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gridsome',
|
id: 'gridsome',
|
||||||
@@ -1187,9 +1120,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://gridsome.org/docs',
|
officialUrl: 'https://gridsome.org/docs',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Gridsome Vue-based static site.',
|
|
||||||
relatedIds: ['gatsby', 'vue', 'nuxt'],
|
relatedIds: ['gatsby', 'vue', 'nuxt'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'readthedocs',
|
id: 'readthedocs',
|
||||||
@@ -1204,9 +1136,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.readthedocs.io',
|
officialUrl: 'https://docs.readthedocs.io',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Read the Docs documentation site.',
|
|
||||||
relatedIds: ['sphinx', 'mkdocs', 'docusaurus'],
|
relatedIds: ['sphinx', 'mkdocs', 'docusaurus'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'sphinx',
|
id: 'sphinx',
|
||||||
@@ -1221,9 +1152,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://www.sphinx-doc.org',
|
officialUrl: 'https://www.sphinx-doc.org',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Sphinx-generated documentation.',
|
|
||||||
relatedIds: ['readthedocs', 'mkdocs', 'docusaurus'],
|
relatedIds: ['readthedocs', 'mkdocs', 'docusaurus'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'readme',
|
id: 'readme',
|
||||||
@@ -1237,9 +1167,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.readme.com',
|
officialUrl: 'https://docs.readme.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your ReadMe API documentation portal.',
|
|
||||||
relatedIds: ['gitbook', 'docusaurus', 'readthedocs'],
|
relatedIds: ['gitbook', 'docusaurus', 'readthedocs'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── JavaScript Frameworks (continued) ───────────────────────────────────
|
// * ─── JavaScript Frameworks (continued) ───────────────────────────────────
|
||||||
@@ -1255,9 +1184,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.flutter.dev',
|
officialUrl: 'https://docs.flutter.dev',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to your Flutter web app via web/index.html.',
|
|
||||||
relatedIds: ['react', 'angular', 'preact'],
|
relatedIds: ['react', 'angular', 'preact'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── Hosting & Deployment (continued) ────────────────────────────────────
|
// * ─── Hosting & Deployment (continued) ────────────────────────────────────
|
||||||
@@ -1274,9 +1202,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://docs.render.com',
|
officialUrl: 'https://docs.render.com',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to sites deployed on Render. Works with any framework.',
|
|
||||||
relatedIds: ['netlify', 'vercel', 'cloudflare-pages'],
|
relatedIds: ['netlify', 'vercel', 'cloudflare-pages'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'firebase',
|
id: 'firebase',
|
||||||
@@ -1290,9 +1217,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://firebase.google.com/docs/hosting',
|
officialUrl: 'https://firebase.google.com/docs/hosting',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to sites deployed on Firebase Hosting.',
|
|
||||||
relatedIds: ['netlify', 'vercel', 'render'],
|
relatedIds: ['netlify', 'vercel', 'render'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// * ─── Platforms & Tools (continued) ───────────────────────────────────────
|
// * ─── Platforms & Tools (continued) ───────────────────────────────────────
|
||||||
@@ -1308,9 +1234,8 @@ export const integrations: Integration[] = [
|
|||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
officialUrl: 'https://amp.dev/documentation',
|
officialUrl: 'https://amp.dev/documentation',
|
||||||
seoDescription:
|
|
||||||
'Add Pulse analytics to Google AMP pages using amp-analytics.',
|
|
||||||
relatedIds: ['gtm', 'wordpress', 'webflow'],
|
relatedIds: ['gtm', 'wordpress', 'webflow'],
|
||||||
|
dedicatedPage: false,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -76,12 +76,31 @@ const nextConfig: NextConfig = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
async redirects() {
|
async redirects() {
|
||||||
|
const removedIntegrations = [
|
||||||
|
'solidjs', 'qwik', 'preact', 'htmx', 'ember',
|
||||||
|
'jekyll', 'docusaurus', 'vitepress', 'hexo', 'mkdocs',
|
||||||
|
'joomla', 'strapi', 'sanity', 'contentful', 'payload',
|
||||||
|
'craftcms', 'statamic', 'typo3', 'kirby', 'grav', 'umbraco',
|
||||||
|
'storyblok', 'prismic', 'shopware', 'magento',
|
||||||
|
'woocommerce', 'bigcommerce', 'prestashop',
|
||||||
|
'blogger', 'substack', 'linktree', 'weebly', 'gitbook',
|
||||||
|
'gridsome', 'readthedocs', 'sphinx', 'readme',
|
||||||
|
'bubble', 'discourse', 'hubspot', 'notion',
|
||||||
|
'cloudflare-pages', 'netlify', 'vercel', 'github-pages',
|
||||||
|
'firebase', 'render', 'flutter', 'amp', 'carrd',
|
||||||
|
]
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
source: '/dashboard',
|
source: '/dashboard',
|
||||||
destination: '/',
|
destination: '/',
|
||||||
permanent: false,
|
permanent: false,
|
||||||
},
|
},
|
||||||
|
...removedIntegrations.map((slug) => ({
|
||||||
|
source: `/integrations/${slug}`,
|
||||||
|
destination: '/integrations/script-tag',
|
||||||
|
permanent: true,
|
||||||
|
})),
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
async rewrites() {
|
async rewrites() {
|
||||||
|
|||||||
1010
package-lock.json
generated
1010
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
"generate:integrations": "npx tsx scripts/generate-integrations.ts",
|
||||||
|
"prebuild": "npm run generate:integrations",
|
||||||
"build": "next build --webpack",
|
"build": "next build --webpack",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
@@ -37,18 +39,21 @@
|
|||||||
"d3-array": "^3.2.4",
|
"d3-array": "^3.2.4",
|
||||||
"d3-scale": "^4.0.2",
|
"d3-scale": "^4.0.2",
|
||||||
"framer-motion": "^12.23.26",
|
"framer-motion": "^12.23.26",
|
||||||
|
"gray-matter": "^4.0.3",
|
||||||
"html-to-image": "^1.11.13",
|
"html-to-image": "^1.11.13",
|
||||||
"iso-3166-2": "^1.0.0",
|
"iso-3166-2": "^1.0.0",
|
||||||
"jspdf": "^4.0.0",
|
"jspdf": "^4.0.0",
|
||||||
"jspdf-autotable": "^5.0.7",
|
"jspdf-autotable": "^5.0.7",
|
||||||
"lucide-react": "^0.577.0",
|
"lucide-react": "^0.577.0",
|
||||||
"next": "^16.1.1",
|
"next": "^16.1.1",
|
||||||
|
"next-mdx-remote": "^6.0.0",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
"react": "^19.2.3",
|
"react": "^19.2.3",
|
||||||
"react-dom": "^19.2.3",
|
"react-dom": "^19.2.3",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"react-use-measure": "^2.1.7",
|
"react-use-measure": "^2.1.7",
|
||||||
"recharts": "^2.15.0",
|
"recharts": "^2.15.0",
|
||||||
|
"remark-gfm": "^4.0.1",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"svg-dotted-map": "^2.0.1",
|
"svg-dotted-map": "^2.0.1",
|
||||||
"swr": "^2.3.3",
|
"swr": "^2.3.3",
|
||||||
|
|||||||
44
scripts/generate-integrations.ts
Normal file
44
scripts/generate-integrations.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import fs from 'fs'
|
||||||
|
import path from 'path'
|
||||||
|
import matter from 'gray-matter'
|
||||||
|
|
||||||
|
const CONTENT_DIR = path.join(process.cwd(), 'content', 'integrations')
|
||||||
|
const OUTPUT_PATH = path.join(process.cwd(), 'lib', 'integration-guides.gen.ts')
|
||||||
|
|
||||||
|
const files = fs.existsSync(CONTENT_DIR)
|
||||||
|
? fs.readdirSync(CONTENT_DIR).filter((f) => f.endsWith('.mdx'))
|
||||||
|
: []
|
||||||
|
|
||||||
|
const guides: { slug: string; title: string; description: string; category: string; date: string }[] = []
|
||||||
|
|
||||||
|
for (const filename of files) {
|
||||||
|
const slug = filename.replace(/\.mdx$/, '')
|
||||||
|
const raw = fs.readFileSync(path.join(CONTENT_DIR, filename), 'utf-8')
|
||||||
|
const { data } = matter(raw)
|
||||||
|
guides.push({
|
||||||
|
slug,
|
||||||
|
title: data.title as string,
|
||||||
|
description: data.description as string,
|
||||||
|
category: data.category as string,
|
||||||
|
date: data.date as string,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
guides.sort((a, b) => a.title.localeCompare(b.title))
|
||||||
|
|
||||||
|
const output = `// Auto-generated from content/integrations/*.mdx — do not edit manually
|
||||||
|
// Run: npm run generate:integrations
|
||||||
|
|
||||||
|
export interface IntegrationGuideSummary {
|
||||||
|
slug: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
category: string
|
||||||
|
date: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const integrationGuides: IntegrationGuideSummary[] = ${JSON.stringify(guides, null, 2)}
|
||||||
|
`
|
||||||
|
|
||||||
|
fs.writeFileSync(OUTPUT_PATH, output, 'utf-8')
|
||||||
|
console.log(`Generated ${guides.length} integration guides → lib/integration-guides.gen.ts`)
|
||||||
Reference in New Issue
Block a user