Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,30 @@ This example runs a search for "coffee" on Google. It returns the results as a P

See the [playground](https://serpapi.com/playground) to generate your own code.

## Response formats

Use `search` for structured results decoded into a PHP object:

```php
$results = $client->search(['q' => 'coffee']);
```

Use `md` for a token-efficient Markdown string optimized for LLMs and AI agents:

```php
$markdown = $client->md(['q' => 'coffee']);
```

Use `html` when you need the raw search-engine response:

```php
$html = $client->html(['q' => 'coffee']);
```

Archived results are also available as Markdown with `$client->searchArchive($searchId, 'md')`.

Learn more about [SerpApi Markdown output](https://serpapi.com/markdown-output).

## Configuration

### API key
Expand Down Expand Up @@ -468,6 +492,9 @@ Now retrieve the previous search from the archive (free of charge):
```php
$archived = $client->searchArchive($search_id);
print_r($archived);

$markdown = $client->searchArchive($search_id, 'md');
echo $markdown;
```

### Account API
Expand Down
27 changes: 27 additions & 0 deletions README.md.erb
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,30 @@ This example runs a search for "coffee" on Google. It returns the results as a P

See the [playground](https://serpapi.com/playground) to generate your own code.

## Response formats

Use `search` for structured results decoded into a PHP object:

```php
$results = $client->search(['q' => 'coffee']);
```

Use `md` for a token-efficient Markdown string optimized for LLMs and AI agents:

```php
$markdown = $client->md(['q' => 'coffee']);
```

Use `html` when you need the raw search-engine response:

```php
$html = $client->html(['q' => 'coffee']);
```

Archived results are also available as Markdown with `$client->searchArchive($searchId, 'md')`.

Learn more about [SerpApi Markdown output](https://serpapi.com/markdown-output).

## Configuration

### API key
Expand Down Expand Up @@ -244,6 +268,9 @@ Now retrieve the previous search from the archive (free of charge):
```php
$archived = $client->searchArchive($search_id);
print_r($archived);

$markdown = $client->searchArchive($search_id, 'md');
echo $markdown;
```

### Account API
Expand Down
23 changes: 17 additions & 6 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ public function search(array $params = []): object
return $this->get('/search', 'json', $params);
}

/**
* Run a search and return Markdown optimized for LLMs and AI agents.
*
* @param array<string, mixed> $params
* @throws SerpApiException
*/
public function md(array $params = []): string
{
return $this->get('/search.md', 'md', $params);
}

/**
* Run a search and return raw HTML.
*
Expand Down Expand Up @@ -122,8 +133,8 @@ public function searchArchive(string $searchId, string $format = 'json')
throw new SerpApiException('search_id must be present');
}

if (!in_array($format, ['json', 'html'], true)) {
throw new SerpApiException('format must be json or html');
if (!in_array($format, ['json', 'html', 'md'], true)) {
throw new SerpApiException('format must be json, html, or md');
}

$safeSearchId = rawurlencode($searchId);
Expand All @@ -137,8 +148,8 @@ public function searchArchive(string $searchId, string $format = 'json')
*/
private function get(string $endpoint, string $format = 'json', array $params = [])
{
if (!in_array($format, ['json', 'html'], true)) {
throw new SerpApiException("Unsupported format '$format'. Expected 'html' or 'json'.");
if (!in_array($format, ['json', 'html', 'md'], true)) {
throw new SerpApiException("Unsupported format '$format'. Expected 'html', 'json', or 'md'.");
}

$apiKey = $params['api_key'] ?? $this->apiKey;
Expand Down Expand Up @@ -171,12 +182,12 @@ private function get(string $endpoint, string $format = 'json', array $params =
throw new SerpApiException('cURL error: ' . $curlError);
}

if ($format === 'html') {
if (in_array($format, ['html', 'md'], true)) {
if ($httpCode === 200) {
return $response;
}

$this->raiseHttpError($httpCode, $endpoint, $query, null, null, 'html');
$this->raiseHttpError($httpCode, $endpoint, $query, null, null, $format);
}

$decoded = json_decode($response);
Expand Down
12 changes: 12 additions & 0 deletions tests/ClientIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ public function testHtml()
$this->assertGreaterThan(10000, strlen($response));
}

public function testMd()
{
$client = $this->serpApiClient();
$response = $client->md($this->searchParams);
$this->assertStringStartsWith('---', $response);
$this->assertStringContainsString('## Organic Results', $response);
}

public function testSearch()
{
$client = $this->serpApiClient();
Expand All @@ -54,5 +62,9 @@ public function testSearchArchive()
$result = $client->search($this->searchParams);
$archived_result = $client->searchArchive($result->search_metadata->id);
$this->assertEquals($result->search_metadata->id, $archived_result->search_metadata->id);

$archived_markdown = $client->searchArchive($result->search_metadata->id, 'md');
$this->assertStringStartsWith('---', $archived_markdown);
$this->assertStringContainsString('## Organic Results', $archived_markdown);
}
}
2 changes: 1 addition & 1 deletion tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function testSearchArchiveThrowsWhenIdEmpty()
public function testSearchArchiveThrowsWhenFormatInvalid()
{
$this->expectException(SerpApiException::class);
$this->expectExceptionMessage('format must be json or html');
$this->expectExceptionMessage('format must be json, html, or md');
$client = new Client('test_key');
$client->searchArchive('abc', 'xml');
}
Expand Down
Loading