diff --git a/mobile/openapi/doc/SmartSearchDto.md b/mobile/openapi/doc/SmartSearchDto.md
index d4ec1a70f6..d5f4c40256 100644
Binary files a/mobile/openapi/doc/SmartSearchDto.md and b/mobile/openapi/doc/SmartSearchDto.md differ
diff --git a/mobile/openapi/lib/model/smart_search_dto.dart b/mobile/openapi/lib/model/smart_search_dto.dart
index 664850db82..0b99acdd66 100644
Binary files a/mobile/openapi/lib/model/smart_search_dto.dart and b/mobile/openapi/lib/model/smart_search_dto.dart differ
diff --git a/mobile/openapi/test/smart_search_dto_test.dart b/mobile/openapi/test/smart_search_dto_test.dart
index 4db3ac0808..5263f7bb6a 100644
Binary files a/mobile/openapi/test/smart_search_dto_test.dart and b/mobile/openapi/test/smart_search_dto_test.dart differ
diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json
index c0e8689850..d5bffc887a 100644
--- a/open-api/immich-openapi-specs.json
+++ b/open-api/immich-openapi-specs.json
@@ -9539,6 +9539,12 @@
           "page": {
             "type": "number"
           },
+          "personIds": {
+            "items": {
+              "type": "string"
+            },
+            "type": "array"
+          },
           "query": {
             "type": "string"
           },
diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts
index b512bce296..12238e40bc 100644
--- a/open-api/typescript-sdk/src/fetch-client.ts
+++ b/open-api/typescript-sdk/src/fetch-client.ts
@@ -671,6 +671,7 @@ export type SmartSearchDto = {
     make?: string;
     model?: string;
     page?: number;
+    personIds?: string[];
     query: string;
     size?: number;
     state?: string;
diff --git a/server/src/domain/search/dto/search.dto.ts b/server/src/domain/search/dto/search.dto.ts
index 877a494e4d..c529f6887b 100644
--- a/server/src/domain/search/dto/search.dto.ts
+++ b/server/src/domain/search/dto/search.dto.ts
@@ -122,6 +122,9 @@ class BaseSearchDto {
 
   @QueryBoolean({ optional: true })
   isNotInAlbum?: boolean;
+
+  @Optional()
+  personIds?: string[];
 }
 
 export class MetadataSearchDto extends BaseSearchDto {
@@ -173,9 +176,6 @@ export class MetadataSearchDto extends BaseSearchDto {
   @Optional()
   @ApiProperty({ enumName: 'AssetOrder', enum: AssetOrder })
   order?: AssetOrder;
-
-  @Optional()
-  personIds?: string[];
 }
 
 export class SmartSearchDto extends BaseSearchDto {
diff --git a/server/src/infra/repositories/search.repository.ts b/server/src/infra/repositories/search.repository.ts
index c8dc5070f7..0ff26a4f5f 100644
--- a/server/src/infra/repositories/search.repository.ts
+++ b/server/src/infra/repositories/search.repository.ts
@@ -22,7 +22,7 @@ import {
 import { ImmichLogger } from '@app/infra/logger';
 import { Injectable } from '@nestjs/common';
 import { InjectRepository } from '@nestjs/typeorm';
-import { Repository } from 'typeorm';
+import { Repository, SelectQueryBuilder } from 'typeorm';
 import { vectorExt } from '../database.config';
 import { DummyValue, GenerateSql } from '../infra.util';
 import { asVector, isValidInteger, paginatedBuilder, searchAssetBuilder } from '../infra.utils';
@@ -81,6 +81,14 @@ export class SearchRepository implements ISearchRepository {
     });
   }
 
+  private createPersonFilter(builder: SelectQueryBuilder<AssetFaceEntity>, personIds: string[]) {
+    return builder
+      .select(`${builder.alias}."assetId"`)
+      .where(`${builder.alias}."personId" IN (:...personIds)`, { personIds })
+      .groupBy(`${builder.alias}."assetId"`)
+      .having(`COUNT(DISTINCT ${builder.alias}."personId") = :personCount`, { personCount: personIds.length });
+  }
+
   @GenerateSql({
     params: [
       { page: 1, size: 100 },
@@ -96,12 +104,21 @@ export class SearchRepository implements ISearchRepository {
   })
   async searchSmart(
     pagination: SearchPaginationOptions,
-    { embedding, userIds, ...options }: SmartSearchOptions,
+    { embedding, userIds, personIds, ...options }: SmartSearchOptions,
   ): Paginated<AssetEntity> {
     let results: PaginationResult<AssetEntity> = { items: [], hasNextPage: false };
 
     await this.assetRepository.manager.transaction(async (manager) => {
       let builder = manager.createQueryBuilder(AssetEntity, 'asset');
+
+      if (personIds?.length) {
+        const assetFaceBuilder = manager.createQueryBuilder(AssetFaceEntity, 'asset_face');
+        const cte = this.createPersonFilter(assetFaceBuilder, personIds);
+        builder
+          .addCommonTableExpression(cte, 'asset_face_ids')
+          .innerJoin('asset_face_ids', 'a', 'a."assetId" = asset.id');
+      }
+
       builder = searchAssetBuilder(builder, options);
       builder
         .innerJoin('asset.smartSearch', 'search')
diff --git a/web/src/lib/components/shared-components/search-bar/search-filter-box.svelte b/web/src/lib/components/shared-components/search-bar/search-filter-box.svelte
index 8d060f4d0d..b05e2d5a3b 100644
--- a/web/src/lib/components/shared-components/search-bar/search-filter-box.svelte
+++ b/web/src/lib/components/shared-components/search-bar/search-filter-box.svelte
@@ -22,7 +22,6 @@
 
 <script lang="ts">
   import Button from '$lib/components/elements/buttons/button.svelte';
-  import { handleError } from '$lib/utils/handle-error';
   import { AssetTypeEnum, type SmartSearchDto, type MetadataSearchDto } from '@immich/sdk';
   import { createEventDispatcher } from 'svelte';
   import { fly } from 'svelte/transition';
@@ -83,14 +82,6 @@
   };
 
   const search = () => {
-    if (filter.context && filter.personIds.size > 0) {
-      handleError(
-        new Error('Context search does not support people filter'),
-        'Context search does not support people filter',
-      );
-      return;
-    }
-
     let type: AssetTypeEnum | undefined = undefined;
     if (filter.mediaType === MediaType.Image) {
       type = AssetTypeEnum.Image;