diff --git a/apps/spruce/src/analytics/distroSettings/useDistroSettingsAnalytics.ts b/apps/spruce/src/analytics/distroSettings/useDistroSettingsAnalytics.ts
index df8dd725c..0fbb9ba31 100644
--- a/apps/spruce/src/analytics/distroSettings/useDistroSettingsAnalytics.ts
+++ b/apps/spruce/src/analytics/distroSettings/useDistroSettingsAnalytics.ts
@@ -6,7 +6,11 @@ import { slugs } from "constants/routes";
 type Action =
   | { name: "Saved distro"; section: string }
   | { name: "Created new distro"; "distro.id": string }
-  | { name: "Clicked duplicate distro"; "distro.id": string };
+  | { name: "Clicked duplicate distro"; "distro.id": string }
+  | {
+      name: "Clicked link";
+      link: "Task Queue" | "Image Build Information" | "Image Event Log";
+    };
 
 export const useDistroSettingsAnalytics = () => {
   const { [slugs.distroId]: distroId } = useParams();
diff --git a/apps/spruce/src/analytics/image/useImageAnalytics.ts b/apps/spruce/src/analytics/image/useImageAnalytics.ts
new file mode 100644
index 000000000..bbb18d2e7
--- /dev/null
+++ b/apps/spruce/src/analytics/image/useImageAnalytics.ts
@@ -0,0 +1,44 @@
+import { ColumnFiltersState, PaginationState } from "@leafygreen-ui/table";
+import { useParams } from "react-router-dom";
+import { useAnalyticsRoot } from "@evg-ui/lib/analytics/hooks";
+import { AnalyticsIdentifier } from "analytics/types";
+import { ImageTabRoutes, slugs } from "constants/routes";
+
+type Action =
+  | {
+      name: "Filtered table";
+      "table.name":
+        | "Image Event Log"
+        | "Operating System"
+        | "Packages"
+        | "Toolchains";
+      "table.filters": ColumnFiltersState;
+    }
+  | {
+      name: "Changed table pagination";
+      "table.name": "Operating System" | "Packages" | "Toolchains";
+      "table.pagination": PaginationState;
+    }
+  | {
+      name: "Changed image";
+      from: string;
+      to: string;
+    }
+  | {
+      name: "Changed tab";
+      tab: ImageTabRoutes;
+    }
+  | {
+      name: "Clicked 'Load more events' button";
+    }
+  | {
+      name: "Used global search";
+      search: string;
+    };
+
+export const useImageAnalytics = () => {
+  const { [slugs.imageId]: imageId } = useParams();
+  return useAnalyticsRoot<Action, AnalyticsIdentifier>("Image", {
+    "image.id": imageId || "",
+  });
+};
diff --git a/apps/spruce/src/analytics/index.ts b/apps/spruce/src/analytics/index.ts
index 15946968e..41c0539b0 100644
--- a/apps/spruce/src/analytics/index.ts
+++ b/apps/spruce/src/analytics/index.ts
@@ -16,3 +16,4 @@ export { useUserPatchesAnalytics } from "./patches/useUserPatchesAnalytics";
 export { useProjectPatchesAnalytics } from "./patches/useProjectPatchesAnalytics";
 export { useVersionAnalytics } from "./version/useVersionAnalytics";
 export { useWaterfallAnalytics } from "./waterfall/useWaterfallAnalytics";
+export { useImageAnalytics } from "./image/useImageAnalytics";
diff --git a/apps/spruce/src/analytics/types.ts b/apps/spruce/src/analytics/types.ts
index 983735edd..1711c4fe0 100644
--- a/apps/spruce/src/analytics/types.ts
+++ b/apps/spruce/src/analytics/types.ts
@@ -20,4 +20,5 @@ export type AnalyticsIdentifier =
   | "TaskQueue"
   | "UserPatches"
   | "Version"
-  | "Waterfall";
+  | "Waterfall"
+  | "Image";
diff --git a/apps/spruce/src/pages/distroSettings/index.tsx b/apps/spruce/src/pages/distroSettings/index.tsx
index 5f77ac746..c76b40a37 100644
--- a/apps/spruce/src/pages/distroSettings/index.tsx
+++ b/apps/spruce/src/pages/distroSettings/index.tsx
@@ -2,6 +2,7 @@ import { useQuery } from "@apollo/client";
 import styled from "@emotion/styled";
 import { sideNavItemSidePadding } from "@leafygreen-ui/side-nav";
 import { useParams, Link, Navigate } from "react-router-dom";
+import { useDistroSettingsAnalytics } from "analytics";
 import Icon from "components/Icon";
 import {
   SideNav,
@@ -33,6 +34,7 @@ import { DistroSettingsTabs } from "./Tabs";
 
 const DistroSettings: React.FC = () => {
   usePageTitle("Distro Settings");
+  const { sendEvent } = useDistroSettingsAnalytics();
   const dispatchToast = useToastContext();
   const { [slugs.distroId]: distroId, [slugs.tab]: currentTab } = useParams<{
     [slugs.distroId]: string;
@@ -89,6 +91,9 @@ const DistroSettings: React.FC = () => {
           <SideNavGroup glyph={<Icon glyph="Link" />} header="Links">
             <SideNavItemLink
               data-cy="navitem-task-queue-link"
+              onClick={() =>
+                sendEvent({ name: "Clicked link", link: "Task Queue" })
+              }
               // @ts-expect-error: FIXME. This comment was added by an automated script.
               to={getTaskQueueRoute(distroId)}
             >
@@ -97,6 +102,12 @@ const DistroSettings: React.FC = () => {
             {showImageVisibilityPage && (
               <SideNavItemLink
                 data-cy="navitem-image-build-information-link"
+                onClick={() =>
+                  sendEvent({
+                    name: "Clicked link",
+                    link: "Image Build Information",
+                  })
+                }
                 to={getImageRoute(
                   data?.distro?.imageId ?? "",
                   ImageTabRoutes.BuildInformation,
@@ -108,6 +119,12 @@ const DistroSettings: React.FC = () => {
             {showImageVisibilityPage && (
               <SideNavItemLink
                 data-cy="navitem-image-event-log-link"
+                onClick={() =>
+                  sendEvent({
+                    name: "Clicked link",
+                    link: "Image Event Log",
+                  })
+                }
                 to={getImageRoute(
                   data?.distro?.imageId ?? "",
                   ImageTabRoutes.EventLog,
diff --git a/apps/spruce/src/pages/image/GeneralTable/index.tsx b/apps/spruce/src/pages/image/GeneralTable/index.tsx
index ecda9ae68..fab98b071 100644
--- a/apps/spruce/src/pages/image/GeneralTable/index.tsx
+++ b/apps/spruce/src/pages/image/GeneralTable/index.tsx
@@ -28,7 +28,7 @@ export const GeneralTable: React.FC<GeneralTableProps> = ({ imageId }) => {
     ImageGeneralQueryVariables
   >(IMAGE_GENERAL, {
     variables: { imageId },
-    onError(err) {
+    onError: (err) => {
       dispatchToast.error(
         `There was an error loading the image general table: ${err.message}`,
       );
diff --git a/apps/spruce/src/pages/image/ImageEventLog/ImageEventLog.tsx b/apps/spruce/src/pages/image/ImageEventLog/ImageEventLog.tsx
index 4931bda8c..022730a0e 100644
--- a/apps/spruce/src/pages/image/ImageEventLog/ImageEventLog.tsx
+++ b/apps/spruce/src/pages/image/ImageEventLog/ImageEventLog.tsx
@@ -3,6 +3,7 @@ import styled from "@emotion/styled";
 import Card from "@leafygreen-ui/card";
 import { SearchInput } from "@leafygreen-ui/search-input";
 import { Subtitle } from "@leafygreen-ui/typography";
+import { useImageAnalytics } from "analytics";
 import { LoadingButton } from "components/Buttons";
 import { size } from "constants/tokens";
 import { ImageEvent } from "gql/generated/types";
@@ -22,6 +23,8 @@ export const ImageEventLog: React.FC<ImageEventLogProps> = ({
   handleFetchMore,
   loading,
 }) => {
+  const { sendEvent } = useImageAnalytics();
+
   const [globalSearch, setGlobalSearch] = useState("");
   const handleGlobalSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
     setGlobalSearch(e.target.value);
@@ -37,6 +40,9 @@ export const ImageEventLog: React.FC<ImageEventLogProps> = ({
           aria-labelledby="event-log-global-search"
           data-cy="event-log-global-search"
           onChange={handleGlobalSearchChange}
+          onSubmit={() => {
+            sendEvent({ name: "Used global search", search: globalSearch });
+          }}
           placeholder="Global search by name"
           value={globalSearch}
         />
@@ -61,7 +67,10 @@ export const ImageEventLog: React.FC<ImageEventLogProps> = ({
         <LoadingButton
           data-cy="load-more-button"
           loading={loading}
-          onClick={handleFetchMore}
+          onClick={() => {
+            sendEvent({ name: "Clicked 'Load more events' button" });
+            handleFetchMore();
+          }}
           variant="primary"
         >
           Load more events
diff --git a/apps/spruce/src/pages/image/ImageEventLog/ImageEventLogTable.tsx b/apps/spruce/src/pages/image/ImageEventLog/ImageEventLogTable.tsx
index 8709ad14a..3465056d6 100644
--- a/apps/spruce/src/pages/image/ImageEventLog/ImageEventLogTable.tsx
+++ b/apps/spruce/src/pages/image/ImageEventLog/ImageEventLogTable.tsx
@@ -9,7 +9,9 @@ import {
   getFilteredRowModel,
   getFacetedUniqueValues,
 } from "@leafygreen-ui/table";
+import { useImageAnalytics } from "analytics";
 import { BaseTable } from "components/Table/BaseTable";
+import { onChangeHandler } from "components/Table/utils";
 import { tableColumnOffset } from "constants/tokens";
 import {
   ImageEventEntry,
@@ -68,7 +70,9 @@ export const ImageEventLogTable: React.FC<ImageEventLogTableProps> = ({
   entries,
   globalFilter,
 }) => {
+  const { sendEvent } = useImageAnalytics();
   const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
+
   const tableContainerRef = useRef<HTMLDivElement>(null);
   const table = useLeafyGreenTable<ImageEventEntry>({
     columns,
@@ -77,7 +81,15 @@ export const ImageEventLogTable: React.FC<ImageEventLogTableProps> = ({
     defaultColumn: {
       enableColumnFilter: false,
     },
-    onColumnFiltersChange: setColumnFilters,
+    onColumnFiltersChange: onChangeHandler<ColumnFiltersState>(
+      setColumnFilters,
+      (f) =>
+        sendEvent({
+          name: "Filtered table",
+          "table.name": "Image Event Log",
+          "table.filters": f,
+        }),
+    ),
     state: {
       columnFilters,
       globalFilter,
diff --git a/apps/spruce/src/pages/image/ImageSelect/index.tsx b/apps/spruce/src/pages/image/ImageSelect/index.tsx
index d7ab0d156..f6a903251 100644
--- a/apps/spruce/src/pages/image/ImageSelect/index.tsx
+++ b/apps/spruce/src/pages/image/ImageSelect/index.tsx
@@ -2,6 +2,7 @@ import { useQuery } from "@apollo/client";
 import { Combobox, ComboboxOption } from "@leafygreen-ui/combobox";
 import { Skeleton } from "@leafygreen-ui/skeleton-loader";
 import { useNavigate } from "react-router-dom";
+import { useImageAnalytics } from "analytics";
 import { getImageRoute } from "constants/routes";
 import { zIndex } from "constants/tokens";
 import { useToastContext } from "context/toast";
@@ -13,6 +14,7 @@ interface ImageSelectProps {
 }
 
 export const ImageSelect: React.FC<ImageSelectProps> = ({ selectedImage }) => {
+  const { sendEvent } = useImageAnalytics();
   const navigate = useNavigate();
 
   const dispatchToast = useToastContext();
@@ -36,6 +38,11 @@ export const ImageSelect: React.FC<ImageSelectProps> = ({ selectedImage }) => {
         label="Images"
         // @ts-expect-error: onChange expects type string | null
         onChange={(imageId: string) => {
+          sendEvent({
+            name: "Changed image",
+            from: selectedImage,
+            to: imageId,
+          });
           navigate(getImageRoute(imageId));
         }}
         placeholder="Select an image"
diff --git a/apps/spruce/src/pages/image/OperatingSystemTable/index.tsx b/apps/spruce/src/pages/image/OperatingSystemTable/index.tsx
index 8702506c0..0ca66e041 100644
--- a/apps/spruce/src/pages/image/OperatingSystemTable/index.tsx
+++ b/apps/spruce/src/pages/image/OperatingSystemTable/index.tsx
@@ -6,7 +6,9 @@ import {
   ColumnFiltersState,
   PaginationState,
 } from "@leafygreen-ui/table";
+import { useImageAnalytics } from "analytics";
 import { BaseTable } from "components/Table/BaseTable";
+import { onChangeHandler } from "components/Table/utils";
 import { DEFAULT_PAGE_SIZE } from "constants/index";
 import { useToastContext } from "context/toast";
 import {
@@ -24,12 +26,14 @@ export const OperatingSystemTable: React.FC<OperatingSystemTableProps> = ({
   imageId,
 }) => {
   const dispatchToast = useToastContext();
+  const { sendEvent } = useImageAnalytics();
 
   const [pagination, setPagination] = useState<PaginationState>({
     pageIndex: 0,
     pageSize: DEFAULT_PAGE_SIZE,
   });
   const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
+
   const { data: osData, loading } = useQuery<
     ImageOperatingSystemQuery,
     ImageOperatingSystemQueryVariables
@@ -71,8 +75,22 @@ export const OperatingSystemTable: React.FC<OperatingSystemTableProps> = ({
       pagination,
       columnFilters,
     },
-    onColumnFiltersChange: setColumnFilters,
-    onPaginationChange: setPagination,
+    onColumnFiltersChange: onChangeHandler<ColumnFiltersState>(
+      setColumnFilters,
+      (f) =>
+        sendEvent({
+          name: "Filtered table",
+          "table.name": "Operating System",
+          "table.filters": f,
+        }),
+    ),
+    onPaginationChange: onChangeHandler<PaginationState>(setPagination, (p) =>
+      sendEvent({
+        name: "Changed table pagination",
+        "table.name": "Operating System",
+        "table.pagination": p,
+      }),
+    ),
   });
 
   return (
diff --git a/apps/spruce/src/pages/image/PackagesTable/index.tsx b/apps/spruce/src/pages/image/PackagesTable/index.tsx
index 2b3ca159b..1aa90583b 100644
--- a/apps/spruce/src/pages/image/PackagesTable/index.tsx
+++ b/apps/spruce/src/pages/image/PackagesTable/index.tsx
@@ -6,7 +6,9 @@ import {
   ColumnFiltersState,
   PaginationState,
 } from "@leafygreen-ui/table";
+import { useImageAnalytics } from "analytics";
 import { BaseTable } from "components/Table/BaseTable";
+import { onChangeHandler } from "components/Table/utils";
 import { DEFAULT_PAGE_SIZE } from "constants/index";
 import { useToastContext } from "context/toast";
 import {
@@ -22,11 +24,13 @@ type PackagesTableProps = {
 
 export const PackagesTable: React.FC<PackagesTableProps> = ({ imageId }) => {
   const dispatchToast = useToastContext();
+  const { sendEvent } = useImageAnalytics();
   const [pagination, setPagination] = useState<PaginationState>({
     pageIndex: 0,
     pageSize: DEFAULT_PAGE_SIZE,
   });
   const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
+
   const { data: packagesData, loading } = useQuery<
     ImagePackagesQuery,
     ImagePackagesQueryVariables
@@ -68,8 +72,22 @@ export const PackagesTable: React.FC<PackagesTableProps> = ({ imageId }) => {
       pagination,
       columnFilters,
     },
-    onColumnFiltersChange: setColumnFilters,
-    onPaginationChange: setPagination,
+    onColumnFiltersChange: onChangeHandler<ColumnFiltersState>(
+      setColumnFilters,
+      (f) =>
+        sendEvent({
+          name: "Filtered table",
+          "table.name": "Packages",
+          "table.filters": f,
+        }),
+    ),
+    onPaginationChange: onChangeHandler<PaginationState>(setPagination, (p) =>
+      sendEvent({
+        name: "Changed table pagination",
+        "table.name": "Packages",
+        "table.pagination": p,
+      }),
+    ),
   });
 
   return (
diff --git a/apps/spruce/src/pages/image/ToolchainsTable/index.tsx b/apps/spruce/src/pages/image/ToolchainsTable/index.tsx
index e0670323c..f2a912b1d 100644
--- a/apps/spruce/src/pages/image/ToolchainsTable/index.tsx
+++ b/apps/spruce/src/pages/image/ToolchainsTable/index.tsx
@@ -6,7 +6,9 @@ import {
   ColumnFiltersState,
   PaginationState,
 } from "@leafygreen-ui/table";
+import { useImageAnalytics } from "analytics";
 import { BaseTable } from "components/Table/BaseTable";
+import { onChangeHandler } from "components/Table/utils";
 import { DEFAULT_PAGE_SIZE } from "constants/index";
 import { useToastContext } from "context/toast";
 import {
@@ -24,6 +26,7 @@ export const ToolchainsTable: React.FC<ToolchainsTableProps> = ({
   imageId,
 }) => {
   const dispatchToast = useToastContext();
+  const { sendEvent } = useImageAnalytics();
   const [pagination, setPagination] = useState<PaginationState>({
     pageIndex: 0,
     pageSize: DEFAULT_PAGE_SIZE,
@@ -67,8 +70,22 @@ export const ToolchainsTable: React.FC<ToolchainsTableProps> = ({
     },
     manualFiltering: true,
     manualPagination: true,
-    onColumnFiltersChange: setColumnFilters,
-    onPaginationChange: setPagination,
+    onColumnFiltersChange: onChangeHandler<ColumnFiltersState>(
+      setColumnFilters,
+      (f) =>
+        sendEvent({
+          name: "Filtered table",
+          "table.name": "Toolchains",
+          "table.filters": f,
+        }),
+    ),
+    onPaginationChange: onChangeHandler<PaginationState>(setPagination, (p) =>
+      sendEvent({
+        name: "Changed table pagination",
+        "table.name": "Toolchains",
+        "table.pagination": p,
+      }),
+    ),
     state: {
       pagination,
       columnFilters,
diff --git a/apps/spruce/src/pages/image/index.tsx b/apps/spruce/src/pages/image/index.tsx
index 4f8ae979c..98b648eef 100644
--- a/apps/spruce/src/pages/image/index.tsx
+++ b/apps/spruce/src/pages/image/index.tsx
@@ -1,6 +1,7 @@
 import styled from "@emotion/styled";
 import { sideNavItemSidePadding } from "@leafygreen-ui/side-nav";
 import { Link, useParams, Navigate } from "react-router-dom";
+import { useImageAnalytics } from "analytics";
 import {
   SideNav,
   SideNavGroup,
@@ -20,9 +21,9 @@ const Image: React.FC = () => {
     [slugs.imageId]: string;
     [slugs.tab]: ImageTabRoutes;
   }>();
+  const { sendEvent } = useImageAnalytics();
 
   const { image: firstImage } = useFirstImage();
-
   const selectedImage = imageId ?? firstImage;
 
   if (
@@ -50,6 +51,7 @@ const Image: React.FC = () => {
               active={tab === currentTab}
               as={Link}
               data-cy={`navitem-${tab}`}
+              onClick={() => sendEvent({ name: "Changed tab", tab })}
               to={getImageRoute(selectedImage, tab)}
             >
               {getTabTitle(tab).title}