diff --git a/components/Competitors/ComparisonTable.tsx b/components/Competitors/ComparisonTable.tsx
new file mode 100644
index 00000000..fcee0ae9
--- /dev/null
+++ b/components/Competitors/ComparisonTable.tsx
@@ -0,0 +1,84 @@
+import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid'
+import Image from 'next/image'
+import { HiCheckCircle, HiDotsCircleHorizontal, HiXCircle } from 'react-icons/hi'
+import highlightlogosmall from '../../public/images/logo-on-dark.png'
+import logrocketlogofull from '../../public/images/logrocketlogofull.png'
+import logrocketlogosmall from '../../public/images/logrocketlogosmall.png'
+import { HighlightLogo } from '../common/HighlightLogo/HighlightLogo'
+import { Typography } from '../common/Typography/Typography'
+import { ComparisonTableRow, ComparisonTableSection, Competitor } from './competitors'
+
+export default function ComparisonTable(props: { competitor: Competitor }) {
+ if (!props.competitor) {
+ return
No Competitor Loaded
+ }
+
+ return (
+
+ {props.competitor.sections.map((section: ComparisonTableSection, i) => (
+
+
+
+ {section.title}
+
+
+
+ {section.rows.map((row: ComparisonTableRow, j) => (
+
+
+ {row.feature}
+
+
+
+
+
+ {row.highlight == 1 ? (
+
+ ) : (
+
+
+
+ {row.highlight == 0.5 && (
+
+
+ Coming soon
+
+
+ )}
+
+ )}
+
+
+ {row.competitor ? (
+
+ ) : (
+
+ )}
+
+
+
+ ))}
+
+ ))}
+
+ )
+}
diff --git a/components/Competitors/competitors.ts b/components/Competitors/competitors.ts
new file mode 100644
index 00000000..33eb82b7
--- /dev/null
+++ b/components/Competitors/competitors.ts
@@ -0,0 +1,120 @@
+import { StaticImageData } from 'next/image'
+
+export type ComparisonTableRow = {
+ feature: string
+ highlight: 0 | 0.5 | 1
+ competitor: 0 | 1
+ tooltip?: string
+}
+
+export type ComparisonTableSection = {
+ title: string
+ rows: ComparisonTableRow[]
+}
+
+export type Competitor = {
+ slug: string
+ name: string
+ header: string
+ subheader: string
+ subHeader2: string
+ logo?: StaticImageData
+ sections: ComparisonTableSection[]
+}
+
+export const COMPETITORS: { [k: string]: Competitor } = {
+ 'log-rocket': {
+ slug: 'log-rocket',
+ name: 'LogRocket',
+ header: 'The Open Source Logrocket Alternative.',
+ subheader: 'Pixel-perfect video replay of your web application. Step into the shoes of your users.',
+ subHeader2: 'An Open Source, Fullstack Alternative to Logrocket. Get Started for free in minutes.',
+ sections: [
+ {
+ title: 'General',
+ rows: [
+ {
+ feature: 'Unlimited Team Members',
+ highlight: 1,
+ competitor: 1,
+ },
+ {
+ feature: 'Unlimited Team Members',
+ highlight: 1,
+ competitor: 0,
+ },
+ {
+ feature: 'Unlimited Team Members',
+ highlight: 1,
+ competitor: 1,
+ },
+ {
+ feature: 'Unlimited Team Members',
+ highlight: 0.5,
+ competitor: 1,
+ },
+ {
+ feature: 'Unlimited Team Members',
+ highlight: 1,
+ competitor: 1,
+ },
+ ],
+ },
+ {
+ title: 'Session Replay',
+ rows: [
+ {
+ feature: 'Commenting / Mentions',
+ highlight: 1,
+ competitor: 1,
+ },
+ {
+ feature: 'Heatmaps',
+ highlight: 1,
+ competitor: 0,
+ },
+ {
+ feature: 'Session Sharing',
+ highlight: 1,
+ competitor: 1,
+ },
+ {
+ feature: 'Privacy SDKs',
+ highlight: 0.5,
+ competitor: 0,
+ },
+ {
+ feature: 'Embedded Error Monitoring',
+ highlight: 1,
+ competitor: 1,
+ },
+ {
+ feature: 'Canvas & WebGL Recording',
+ highlight: 1,
+ competitor: 1,
+ },
+ {
+ feature: 'Session-level Debugging Data',
+ highlight: 1,
+ competitor: 1,
+ },
+ ],
+ },
+ {
+ title: 'Error Monitoring',
+ rows: [
+ {
+ feature: 'Embedded Session Replay',
+ highlight: 1,
+ competitor: 1,
+ },
+ {
+ feature: 'Support for Backend SDKs',
+ highlight: 1,
+ competitor: 0,
+ },
+ ],
+ },
+ ],
+ },
+}
diff --git a/pages/session-replay/[slug].tsx b/pages/session-replay/[slug].tsx
new file mode 100644
index 00000000..7093b607
--- /dev/null
+++ b/pages/session-replay/[slug].tsx
@@ -0,0 +1,162 @@
+import classNames from 'classnames'
+import { GetStaticPaths, GetStaticProps } from 'next'
+import Image from 'next/image'
+import Link from 'next/link'
+import { useState } from 'react'
+import { MdKeyboardReturn } from 'react-icons/md'
+import { PrimaryButton } from '../../components/common/Buttons/PrimaryButton'
+import { FooterCallToAction } from '../../components/common/CallToAction/FooterCallToAction'
+import { OSSCallToAction } from '../../components/common/CallToAction/OSSCallToAction'
+import Footer from '../../components/common/Footer/Footer'
+import Navbar from '../../components/common/Navbar/Navbar'
+import { Section } from '../../components/common/Section/Section'
+import { Typography } from '../../components/common/Typography/Typography'
+import CompetitorTable from '../../components/Competitors/ComparisonTable'
+import { Competitor, COMPETITORS } from '../../components/Competitors/competitors'
+import { CompaniesReel } from '../../components/Home/CompaniesReel/CompaniesReel'
+import { CustomerReviewTrack } from '../../components/Home/CustomerReviewTrack'
+import homeStyles from '../../components/Home/Home.module.scss'
+import errorMonitoringHero from '../../public/images/features/errorMonitoringHero.png'
+import loggingHero from '../../public/images/features/loggingHero.png'
+import sessionReplayHero from '../../public/images/features/sessionReplayHero.png'
+import sessionscreenshot from '../../public/images/sessionscreenshot.png'
+
+import { AnimateFeatureHeroRight, AnimateFeatureHeroXL } from '../../components/Animate'
+
+const CompetitorComparisonPage = ({ competitor }: { competitor: Competitor }) => {
+ const [imageLoaded, setImageLoaded] = useState(false)
+
+ return (
+
+
+
+
+
+
+
+
+
+ Explore highlight.io
+
+
+
+
+
+
+
+
+
The Open Source {competitor.name} alternative.
+
+
+ {competitor.subheader}
+
+
+
+
+ Get started for free
+
+
+
+
+ Read our docs
+
+
+
+
+
+
+
+ setImageLoaded(true)}
+ />
+
+
+ setImageLoaded(true)}
+ />
+
+
setImageLoaded(true)}
+ />
+
+
+
+
+
+
+ How does highlight.io stack up?
+
+
+
+ {competitor.subHeader2}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Don't take our word. Read our customer review section →
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export const getStaticPaths: GetStaticPaths = async () => {
+ return {
+ paths: Object.keys(COMPETITORS).map((k: string) => ({
+ params: { slug: k },
+ })),
+ fallback: 'blocking',
+ }
+}
+
+//Gets list of products from products.ts
+export const getStaticProps: GetStaticProps = async ({ params }) => {
+ const slug = params?.slug as string
+
+ // Handle event slugs which don't exist
+ if (!COMPETITORS[slug]) {
+ return {
+ notFound: true,
+ }
+ }
+
+ return {
+ props: {
+ competitor: COMPETITORS[slug],
+ },
+ }
+}
+
+export default CompetitorComparisonPage
diff --git a/public/images/logrocketlogofull.png b/public/images/logrocketlogofull.png
new file mode 100644
index 00000000..c883bd22
Binary files /dev/null and b/public/images/logrocketlogofull.png differ
diff --git a/public/images/logrocketlogosmall.png b/public/images/logrocketlogosmall.png
new file mode 100644
index 00000000..64e80a70
Binary files /dev/null and b/public/images/logrocketlogosmall.png differ