diff --git a/.changeset/live-tail-refresh-interval.md b/.changeset/live-tail-refresh-interval.md
new file mode 100644
index 0000000000..120bd2c856
--- /dev/null
+++ b/.changeset/live-tail-refresh-interval.md
@@ -0,0 +1,8 @@
+---
+"@hyperdx/app": patch
+---
+
+feat: add ability to change live tail refresh interval
+
+Adds a dropdown selector in the search page that allows users to configure the live tail refresh interval. Options include 1s, 2s, 4s (default), 10s, and 30s. The selected refresh frequency is persisted in the URL query parameter.
+
diff --git a/packages/app/src/DBSearchPage.tsx b/packages/app/src/DBSearchPage.tsx
index 709573ed31..35143bc8f0 100644
--- a/packages/app/src/DBSearchPage.tsx
+++ b/packages/app/src/DBSearchPage.tsx
@@ -49,8 +49,10 @@ import {
Menu,
Modal,
Paper,
+ Select,
Stack,
Text,
+ Tooltip,
} from '@mantine/core';
import {
useDebouncedCallback,
@@ -123,6 +125,15 @@ import { SearchConfig } from './types';
import searchPageStyles from '../styles/SearchPage.module.scss';
+const LIVE_TAIL_REFRESH_FREQUENCY_OPTIONS = [
+ { value: '1000', label: '1s' },
+ { value: '2000', label: '2s' },
+ { value: '4000', label: '4s' },
+ { value: '10000', label: '10s' },
+ { value: '30000', label: '30s' },
+];
+const DEFAULT_REFRESH_FREQUENCY = 4000;
+
const ALLOWED_SOURCE_KINDS = [SourceKind.Log, SourceKind.Trace];
const SearchConfigSchema = z.object({
select: z.string(),
@@ -1014,6 +1025,11 @@ function DBSearchPage() {
parseAsInteger.withDefault(LIVE_TAIL_DURATION_MS),
);
+ const [refreshFrequency, setRefreshFrequency] = useQueryState(
+ 'refreshFrequency',
+ parseAsInteger.withDefault(DEFAULT_REFRESH_FREQUENCY),
+ );
+
const updateRelativeTimeInputValue = useCallback((interval: number) => {
const label = getRelativeTimeOptionLabel(interval);
if (label) {
@@ -1032,7 +1048,7 @@ function DBSearchPage() {
useLiveUpdate({
isLive,
interval,
- refreshFrequency: 4000,
+ refreshFrequency,
onTimeRangeSelect,
pause: isAnyQueryFetching || !queryReady || !isTabVisible,
});
@@ -1583,6 +1599,24 @@ function DBSearchPage() {
isLive && interval !== LIVE_TAIL_DURATION_MS
}
/>
+ {isLive && (
+
+
+ )}