diff --git a/.changeset/analytics-det-tyckte-inte-jag.md b/.changeset/analytics-det-tyckte-inte-jag.md
new file mode 100644
index 0000000000..bc486e64c4
--- /dev/null
+++ b/.changeset/analytics-det-tyckte-inte-jag.md
@@ -0,0 +1,6 @@
+---
+'@backstage/core-components': patch
+'@backstage/plugin-catalog-react': patch
+---
+
+The `` component now accepts a `noTrack` prop, which prevents the `click` event from being captured by the Analytics API. This can be used if tracking is explicitly not warranted, or in order to use custom link tracking in specific situations.
diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md
index 88e7f4efab..47ca3d3cf8 100644
--- a/packages/core-components/api-report.md
+++ b/packages/core-components/api-report.md
@@ -599,6 +599,7 @@ export function Link(props: LinkProps): JSX.Element;
export type LinkProps = LinkProps_2 &
LinkProps_3 & {
component?: ElementType;
+ noTrack?: boolean;
};
// Warning: (ae-missing-release-tag) "LoginRequestListItemClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
diff --git a/packages/core-components/src/components/Link/Link.test.tsx b/packages/core-components/src/components/Link/Link.test.tsx
index 2d00aad827..8c6ed54d76 100644
--- a/packages/core-components/src/components/Link/Link.test.tsx
+++ b/packages/core-components/src/components/Link/Link.test.tsx
@@ -76,6 +76,33 @@ describe('', () => {
});
});
+ it('does not capture click when noTrack is set', async () => {
+ const linkText = 'Navigate!';
+ const analyticsApi = new MockAnalyticsApi();
+ const customOnClick = jest.fn();
+
+ const { getByText } = render(
+ wrapInTestApp(
+
+
+ {linkText}
+
+ ,
+ ),
+ );
+
+ fireEvent.click(getByText(linkText));
+
+ // Analytics event should have been fired.
+ await waitFor(() => {
+ // Custom onClick handler should have been fired.
+ expect(customOnClick).toHaveBeenCalled();
+
+ // But there should be no analytics event.
+ expect(analyticsApi.getEvents()).toHaveLength(0);
+ });
+ });
+
describe('isExternalUri', () => {
it.each([
[true, 'http://'],
diff --git a/packages/core-components/src/components/Link/Link.tsx b/packages/core-components/src/components/Link/Link.tsx
index 8866150f86..30796c4e05 100644
--- a/packages/core-components/src/components/Link/Link.tsx
+++ b/packages/core-components/src/components/Link/Link.tsx
@@ -29,6 +29,7 @@ export const isExternalUri = (uri: string) => /^([a-z+.-]+):/.test(uri);
export type LinkProps = MaterialLinkProps &
RouterLinkProps & {
component?: ElementType;
+ noTrack?: boolean;
};
declare function LinkType(props: LinkProps): JSX.Element;
@@ -62,7 +63,7 @@ const getNodeText = (node: React.ReactNode): string => {
* - Captures Link clicks as analytics events.
*/
const ActualLink = React.forwardRef(
- ({ onClick, ...props }, ref) => {
+ ({ onClick, noTrack, ...props }, ref) => {
const analytics = useAnalytics();
const to = String(props.to);
const linkText = getNodeText(props.children) || to;
@@ -71,7 +72,9 @@ const ActualLink = React.forwardRef(
const handleClick = (event: React.MouseEvent) => {
onClick?.(event);
- analytics.captureEvent('click', linkText, { attributes: { to } });
+ if (!noTrack) {
+ analytics.captureEvent('click', linkText, { attributes: { to } });
+ }
};
return external ? (
diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md
index 398bace903..8c3ba0daa3 100644
--- a/plugins/catalog-react/api-report.md
+++ b/plugins/catalog-react/api-report.md
@@ -573,6 +573,7 @@ export const EntityRefLink: React_2.ForwardRefExoticComponent<
| 'gutterBottom'
| 'paragraph'
| 'variantMapping'
+ | 'noTrack'
| 'TypographyClasses'
| 'entityRef'
| 'defaultKind'