Skip to content

Commit 9ad51a2

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/lf-2189-write-blog-post-about-code-based-evals
2 parents 039aa4e + b232880 commit 9ad51a2

90 files changed

Lines changed: 1320 additions & 573 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/layout.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ import {
1111
} from "@/lib/og-url";
1212
import { PostHogProvider } from "@/components/analytics/PostHogProvider";
1313
import { AISearch } from "@/components/inkeep/search";
14+
import { Hubspot } from "@/components/analytics/hubspot";
15+
import { GoogleAds } from "@/components/analytics/google-ads";
16+
import { LinkedInInsightTag } from "@/components/analytics/linkedin-ads";
17+
import { RedditPixel } from "@/components/analytics/reddit-ads";
18+
import { TwitterPixel } from "@/components/analytics/twitter-ads";
19+
import { ConversionTracker } from "@/components/analytics/ConversionTracker";
20+
import "../style.css";
21+
import "@vidstack/react/player/styles/base.css";
22+
import "../src/overrides.css";
1423

1524
const interVariable = Inter({
1625
subsets: ["latin"],
@@ -31,11 +40,6 @@ const f37Analog = localFont({
3140
display: "swap",
3241
weight: "500",
3342
});
34-
import { Hubspot } from "@/components/analytics/hubspot";
35-
import { GoogleAds } from "@/components/analytics/google-ads";
36-
import "../style.css";
37-
import "@vidstack/react/player/styles/base.css";
38-
import "../src/overrides.css";
3943

4044
const defaultOgImageUrl = buildDefaultSiteOgImageUrl();
4145

@@ -92,6 +96,10 @@ export default function RootLayout({
9296
<>
9397
<GoogleTagManager gtmId="GTM-NGLK4TZX" />
9498
<GoogleAds />
99+
<LinkedInInsightTag />
100+
<RedditPixel />
101+
<TwitterPixel />
102+
<ConversionTracker />
95103
<Hubspot />
96104
<Script
97105
id="cookieyes"

components-mdx/team-members.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@
2121
| **Mark Salpeter** | Product Engineer | [Twitter](https://x.com/marksalpeter), [LinkedIn](https://www.linkedin.com/in/marksalpeter/), [GitHub](https://github.com/marksalpeter) |
2222
| **Caleb Seeling** | Support Engineer | [LinkedIn](https://www.linkedin.com/in/calebloveseeling/), [GitHub](https://github.com/CodeCLS) |
2323
| **Niklas Semmler** | Backend Engineer | [LinkedIn](https://www.linkedin.com/in/nsemmler/), [GitHub](https://github.com/niklassemmler) |
24+
| **Nikita Kabardin** | Frontend Engineer | [LinkedIn](https://www.linkedin.com/in/nkabardin/), [GitHub](https://github.com/nkabardin) |

components/ContactSalesForm.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ import {
2828
FORM_FIELDS,
2929
type ContactFormData,
3030
} from "@/lib/contact-sales-form";
31-
import {
32-
GOOGLE_ADS_CONVERSIONS,
33-
reportGoogleAdsConversion,
34-
} from "@/lib/google-ads";
31+
import { reportTalkToUsConversion } from "@/lib/ad-conversions";
3532

3633
function RequiredMarker({ required }: { required: boolean }) {
3734
if (!required) {
@@ -94,7 +91,7 @@ export function ContactSalesForm() {
9491
}
9592

9693
setIsSuccess(true);
97-
reportGoogleAdsConversion(GOOGLE_ADS_CONVERSIONS.talkToUsFormSubmit);
94+
reportTalkToUsConversion();
9895
} catch (err) {
9996
setError(err instanceof Error ? err.message : "An error occurred");
10097
} finally {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"use client";
2+
3+
import { useEffect } from "react";
4+
import { LAUNCH_APP_CTA_SELECTOR } from "@/lib/google-ads";
5+
import { reportLaunchAppConversion } from "@/lib/ad-conversions";
6+
7+
// Reports the "launch app" conversion (sign up / sign in) across every ad
8+
// platform whenever a user clicks a CTA that navigates to the Langfuse cloud
9+
// app. CTAs opt in via the `data-launch-app-cta` attribute, so incidental
10+
// cloud.langfuse.com links (e.g. in docs/blog content) are not counted. A
11+
// single delegated listener keeps this working for every marked CTA.
12+
export function ConversionTracker() {
13+
useEffect(() => {
14+
// Capture phase runs before button onClick handlers, so CTAs that
15+
// preventDefault to navigate programmatically are still tracked.
16+
const handler = (event: MouseEvent) => {
17+
const target = event.target as Element | null;
18+
if (!target?.closest(LAUNCH_APP_CTA_SELECTOR)) return;
19+
reportLaunchAppConversion();
20+
};
21+
22+
document.addEventListener("click", handler, true);
23+
return () => document.removeEventListener("click", handler, true);
24+
}, []);
25+
26+
return null;
27+
}

components/analytics/google-ads.tsx

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,10 @@
1-
"use client";
2-
3-
import { useEffect } from "react";
41
import Script from "next/script";
5-
import {
6-
GOOGLE_ADS_CONVERSIONS,
7-
GOOGLE_ADS_ID,
8-
LAUNCH_APP_CTA_SELECTOR,
9-
reportGoogleAdsConversion,
10-
} from "@/lib/google-ads";
2+
import { GOOGLE_ADS_ID } from "@/lib/google-ads";
113

12-
// Loads the Google Ads global site tag and reports the "launch app" conversion
13-
// (sign ups / sign ins) whenever a user clicks a CTA that navigates to the
14-
// Langfuse cloud app. CTAs opt in via the `data-launch-app-cta` attribute, so
15-
// incidental cloud.langfuse.com links (e.g. in docs/blog content) are not
16-
// counted as conversions. A delegated listener keeps this working for every
17-
// marked CTA without touching each button.
4+
// Google Ads global site tag (gtag.js). Conversions are reported via
5+
// `reportGoogleAdsConversion` (see lib/ad-conversions.ts), and launch-app CTA
6+
// clicks are tracked by the shared ConversionTracker.
187
export function GoogleAds() {
19-
useEffect(() => {
20-
// Capture phase runs before button onClick handlers, so CTAs that
21-
// preventDefault to navigate programmatically are still tracked.
22-
const handler = (event: MouseEvent) => {
23-
const target = event.target as Element | null;
24-
if (!target?.closest(LAUNCH_APP_CTA_SELECTOR)) return;
25-
reportGoogleAdsConversion(GOOGLE_ADS_CONVERSIONS.launchApp, {
26-
value: 1.0,
27-
currency: "USD",
28-
});
29-
};
30-
31-
document.addEventListener("click", handler, true);
32-
return () => document.removeEventListener("click", handler, true);
33-
}, []);
34-
358
return (
369
<>
3710
<Script
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import Script from "next/script";
2+
import { LINKEDIN_PARTNER_ID, isLinkedInEnabled } from "@/lib/linkedin-ads";
3+
4+
// LinkedIn Insight Tag base script. Conversions are reported via
5+
// `reportLinkedInConversion` (see lib/ad-conversions.ts).
6+
export function LinkedInInsightTag() {
7+
if (!isLinkedInEnabled) return null;
8+
9+
return (
10+
<>
11+
<Script id="linkedin-partner-id" strategy="afterInteractive">
12+
{`_linkedin_partner_id = "${LINKEDIN_PARTNER_ID}";
13+
window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];
14+
window._linkedin_data_partner_ids.push(_linkedin_partner_id);`}
15+
</Script>
16+
<Script id="linkedin-insight" strategy="afterInteractive">
17+
{`(function(l) {
18+
if (!l){window.lintrk = function(a,b){window.lintrk.q.push([a,b])};
19+
window.lintrk.q=[]}
20+
var s = document.getElementsByTagName("script")[0];
21+
var b = document.createElement("script");
22+
b.type = "text/javascript";b.async = true;
23+
b.src = "https://snap.licdn.com/li.lms-analytics/insight.min.js";
24+
s.parentNode.insertBefore(b, s);})(window.lintrk);`}
25+
</Script>
26+
<noscript>
27+
<img
28+
height="1"
29+
width="1"
30+
style={{ display: "none" }}
31+
alt=""
32+
src={`https://px.ads.linkedin.com/collect/?pid=${LINKEDIN_PARTNER_ID}&fmt=gif`}
33+
/>
34+
</noscript>
35+
</>
36+
);
37+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Script from "next/script";
2+
import { REDDIT_PIXEL_ID, isRedditEnabled } from "@/lib/reddit-ads";
3+
4+
// Reddit Pixel base script (initializes the pixel and tracks PageVisit).
5+
// Conversions are reported via `reportRedditConversion` (see lib/ad-conversions.ts).
6+
export function RedditPixel() {
7+
if (!isRedditEnabled) return null;
8+
9+
return (
10+
<Script id="reddit-pixel" strategy="afterInteractive">
11+
{`!function(w,d){if(!w.rdt){var p=w.rdt=function(){p.sendEvent?p.sendEvent.apply(p,arguments):p.callQueue.push(arguments)};p.callQueue=[];var t=d.createElement("script");t.src="https://www.redditstatic.com/ads/pixel.js",t.async=!0;var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}}(window,document);rdt('init','${REDDIT_PIXEL_ID}');rdt('track','PageVisit');`}
12+
</Script>
13+
);
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Script from "next/script";
2+
import { TWITTER_PIXEL_ID, isTwitterEnabled } from "@/lib/twitter-ads";
3+
4+
// X (Twitter) Pixel base script (universal website tag). Conversions are
5+
// reported via `reportTwitterConversion` (see lib/ad-conversions.ts).
6+
export function TwitterPixel() {
7+
if (!isTwitterEnabled) return null;
8+
9+
return (
10+
<Script id="twitter-pixel" strategy="afterInteractive">
11+
{`!function(e,t,n,s,u,a){e.twq||(s=e.twq=function(){s.exe?s.exe.apply(s,arguments):s.queue.push(arguments);},s.version='1.1',s.queue=[],u=t.createElement(n),u.async=!0,u.src='https://static.ads-twitter.com/uwt.js',a=t.getElementsByTagName(n)[0],a.parentNode.insertBefore(u,a))}(window,document,'script');twq('config','${TWITTER_PIXEL_ID}');`}
12+
</Script>
13+
);
14+
}

components/home/Integrations.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ type MarqueeItem = { label: string; href: string; icon: string };
246246
const marqueeRow1: MarqueeItem[] = [
247247
{
248248
label: "Claude Code",
249-
href: "/integrations/other/claude-code",
249+
href: "/integrations/developer-tools/claude-code",
250250
icon: "/images/integrations/anthropic_icon.png",
251251
},
252252
{
@@ -311,7 +311,7 @@ const marqueeRow1: MarqueeItem[] = [
311311
},
312312
{
313313
label: "Cursor",
314-
href: "/integrations/other/cursor",
314+
href: "/integrations/developer-tools/cursor",
315315
icon: "/images/integrations/cursor_icon.png",
316316
},
317317
{

components/integrations/IntegrationIndex.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,23 @@ const categoryConfig: Record<
2727
title: "Native",
2828
description: "Native integrations with Langfuse",
2929
additionalLinks: additionalLinksFromMeta(nativeIntegrationsMeta),
30+
featuredLinks: [
31+
{
32+
route: "/docs/api-and-data-platform/features/public-api",
33+
frontMatter: { title: "API" },
34+
title: "API",
35+
},
36+
{
37+
route: "/docs/sdk/python/sdk-v3",
38+
frontMatter: { title: "Python SDK" },
39+
title: "Python SDK",
40+
},
41+
{
42+
route: "/docs/sdk/typescript/guide",
43+
frontMatter: { title: "JS/TS SDK" },
44+
title: "JS/TS SDK",
45+
},
46+
],
3047
},
3148
frameworks: {
3249
title: "Frameworks",
@@ -105,6 +122,11 @@ const categoryConfig: Record<
105122
"Use Langfuse data and metrics in your own application and data platform",
106123
additionalLinks: additionalLinksFromMeta(dataPlatformIntegrationsMeta),
107124
},
125+
"developer-tools": {
126+
title: "Developer Tools",
127+
description:
128+
"Trace AI coding assistants, editors, and CLIs, or use Langfuse directly from your editor",
129+
},
108130
other: {
109131
title: "Other",
110132
description: "Other integrations",
@@ -198,7 +220,7 @@ function IntegrationCards({
198220
))}
199221
</Cards>
200222
)}
201-
<div className={featured && featured.length > 0 ? "mt-8" : ""}>
223+
<div className={featured && featured.length > 0 ? "mt-4" : ""}>
202224
<Cards num={3}>
203225
{pages
204226
.filter((p) => !(featured || []).some((f) => f.route === p.route))

0 commit comments

Comments
 (0)