# How to Filter Google Timeline Data by Year in the Google Timeline Visualizer

> Filter Google Timeline data by year using the pointDateKey helper and String.prototype.startsWith. Easily isolate timeline points for specific years with this guide.

- Repository: [mahlernim/google-timeline-visualizer](https://github.com/mahlernim/google-timeline-visualizer)
- Tags: how-to-guide
- Published: 2026-08-22

---

**To filter Google Timeline data by year, generate sortable date keys using the `pointDateKey` helper in [`timeline.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/timeline.ts), then use `String.prototype.startsWith` to isolate points matching your target year.**

The google-timeline-visualizer converts raw Google Takeout exports into structured journeys. When analyzing multi-year location history, isolating specific years requires working with the library's timestamp normalization utilities. This guide demonstrates how to filter Google Timeline data by year using the repository's core data-processing functions.

## Understanding the Timeline Data Structure

Every location entry in the visualizer is stored as a **GeoPoint** object containing a timestamp (`instant`) and an optional original recording date (`recordedDate`). The library normalizes these timestamps through helper functions defined in [`web/src/timeline.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/timeline.ts).

The **`pointDateKey`** function converts any GeoPoint into a consistent `YYYY-MM-DD` string format:

```typescript
// Located in web/src/timeline.ts#L97-L99
function pointDateKey(point: GeoPoint): string {
  return point.recordedDate ?? formatDateKey(point.instant);
}

```

This normalization enables reliable string-based filtering. The function falls back to formatting the `instant` timestamp when `recordedDate` is unavailable, ensuring every point has a comparable date representation.

## Building a Year Selector

### Step 1: Extract Available Years

Before filtering, derive the list of unique years present in your dataset. The **`availableYears`** function slices the first four characters from each date key to isolate the year component:

```typescript
function availableYears(points: GeoPoint[], locale: string): string[] {
  const keys = new Set(points.map(p => pointDateKey(p).slice(0, 4))); // Extract "YYYY"
  return Array.from(keys).sort(); // Returns ["2019", "2020", "2021", ...]
}

```

This produces a sorted array of distinct years suitable for populating UI dropdowns or command-line selectors.

### Step 2: Filter Points by Specific Year

The **`filterByYear`** function leverages the `startsWith` method to retain only points from your target year:

```typescript
function filterByYear(points: GeoPoint[], year: string): GeoPoint[] {
  return points.filter(p => pointDateKey(p).startsWith(year));
}

```

Pass a four-digit year string (e.g., `"2022"`) to receive a filtered `GeoPoint[]` array ready for rendering or export.

## Filtering Across Year Ranges

For multi-year analysis, reuse the existing **`selectRange`** utility found at `web/src/timeline.ts#L20-L25`. This function operates on month keys (`YYYY-MM`), allowing you to construct year-based ranges by anchoring to January and December:

```typescript
function filterByYearRange(
  points: GeoPoint[],
  startYear: string,
  endYear: string,
): GeoPoint[] {
  const start = `${startYear}-01`;  // January of start year
  const end   = `${endYear}-12`;      // December of end year
  return selectRange(points, start, end);
}

```

This approach maintains compatibility with the library's existing range-selection logic while achieving year-level granularity.

## Complete Implementation Workflow

Integrate the filtering functions into your data pipeline as follows:

```typescript
import {
  parseTimelineJson,
  availableYears,
  filterByYear,
} from './timeline';

// 1. Load and parse the Google Takeout JSON
const rawData = await fetch('timeline.json').then(r => r.json());
const points = parseTimelineJson(rawData);   // web/src/timeline.ts#L85-L87

// 2. Build your year selector
const years = availableYears(points, 'en-US');
populateYearDropdown(years);  // Your UI implementation

// 3. Filter for a specific year
const chosenYear = '2021';
const yearPoints = filterByYear(points, chosenYear);

// 4. Render the filtered journey
drawJourney(yearPoints);

```

The **`parseTimelineJson`** function (lines 85-87) handles legacy format detection, deduplication, and normalization before the year filtering logic executes. For best results, apply outlier filtering from [`web/src/outlier.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/outlier.ts) before the year selection step to remove GPS anomalies that might skew your dataset.

## Summary

- **GeoPoint** objects store location data with normalized timestamps in [`web/src/timeline.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/timeline.ts).
- Use **`pointDateKey`** to generate `YYYY-MM-DD` strings for consistent date comparisons.
- Build year selectors with **`availableYears`**, which extracts unique years by slicing the first four characters of date keys.
- Filter specific years using **`filterByYear`** with the `startsWith` string method.
- Handle year ranges by constructing month-based start/end strings and passing them to **`selectRange`** (lines 20-25).
- Always parse raw JSON through **`parseTimelineJson`** to ensure data normalization before filtering.

## Frequently Asked Questions

### What date format does the visualizer use internally?

The visualizer normalizes all timestamps to **`YYYY-MM-DD`** strings through the `pointDateKey` function. This format ensures lexicographical sorting matches chronological order, making year extraction as simple as reading the first four characters.

### Can I filter by multiple non-consecutive years?

Yes. Simply call `filterByYear` for each target year and merge the results, or modify the filter predicate to check against an array of year strings using `['2020', '2022'].some(year => dateKey.startsWith(year))`.

### Where is the core filtering logic implemented?

All date-key generation and range selection utilities reside in **[`web/src/timeline.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/timeline.ts)**. The `pointDateKey` function is defined at lines 97-99, while `selectRange` appears at lines 20-25. Application-level integration examples are visible in [`web/src/main.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/main.ts).

### Should I remove GPS outliers before filtering by year?

Yes. Apply outlier detection from **[`web/src/outlier.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/outlier.ts)** before year filtering. Spurious GPS points often carry incorrect timestamps that could appear in incorrect years if not filtered first, contaminating your yearly datasets.