To retrieve Google Ads API entities and reporting data, use one of these methods:

- [`GoogleAdsService.SearchStream`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService/SearchStream.md.txt)
- [`GoogleAdsService.Search`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService/Search.md.txt)

Here are the high-level distinctions for the two methods:

|   | GoogleAdsService.SearchStream | GoogleAdsService.Search |
| Suitable for production code | **Yes** | **Yes** |
| Service | [`GoogleAdsService`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService.md.txt) | [`GoogleAdsService`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService.md.txt) |
| Scenario | Fetching objects and reports | Fetching objects and reports |
| Response | **Stream** of [`GoogleAdsRow`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsRow.md.txt) objects | Pages of [`GoogleAdsRow`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsRow.md.txt) objects |
| Response's fields | Only those specified in the query | Only those specified in the query |
| Daily limits | Daily limits based on [access levels](https://developers.google.com/google-ads/api/docs/api-policy/access-levels.md.txt) | Daily limits based on [access levels](https://developers.google.com/google-ads/api/docs/api-policy/access-levels.md.txt) |
|---|---|---|

## `SearchStream` versus `Search`

While [`Search`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService/Search.md.txt) sends multiple paginated requests to
download an entire report, [`SearchStream`](https://developers.google.com/google-ads/api/reference/rpc/v26/GoogleAdsService/SearchStream.md.txt) sends
a single request and initiates a persistent gRPC connection with the Google Ads API
regardless of report size.

For `SearchStream`, data packets start to download immediately in batches of
[`SearchGoogleAdsStreamResponse`](https://developers.google.com/google-ads/api/reference/rpc/v26/SearchGoogleAdsStreamResponse.md.txt) objects. Your code can
iterate over incoming batches as they arrive without waiting for the entire
stream to finish.

By eliminating the round-trip network time required to request each individual
page of a `Search` response, `SearchStream` offers improved performance over
paging, especially for large reports.

### Example

This example looks at a report that consists of `100,000` rows. The following
table breaks down the request and response differences between the two methods:

|   | SearchStream | Search |
| Page size | Not Applicable | 10,000 rows per page |
| Number of API requests | 1 request | 10 requests |
| Number of API responses | 1 continuous stream | 10 responses |
|---|---|---|

### Performance factors

For most use cases, we recommend `SearchStream` over `Search` for the following
reasons:

- **Single-page reports (under 10,000 rows):** There are no significant performance differences between the two methods.
- **Multi-page reports:** `SearchStream` is typically faster because multiple network round trips are avoided, and reading or writing from disk cache is less of a factor.
- **Memory efficiency:** When processing large reports with `SearchStream`, iterate through stream chunks and process rows as they arrive rather than buffering all rows in memory at once to avoid out-of-memory (OOM) errors.
- **Connection resiliency:** Because `SearchStream` relies on a persistent connection, long-running streams can be interrupted by network drops or deadline timeouts. Configure appropriate RPC timeouts and implement retry logic for transient stream errors.

### Rate limits

Daily operation limits for both methods adhere to the standard limits and
[access levels](https://developers.google.com/google-ads/api/docs/api-policy/access-levels.md.txt) of your Google Cloud project. A single logical
report query is counted as one operation toward your daily operation quota
regardless of whether the result is streamed with `SearchStream` or retrieved
across multiple cached pages using `Search` with a `page_token`. However, each
paged `Search` request still counts as an individual RPC call against short-term
rate limits.

### Code example

The following code example demonstrates how to execute a streaming report query
using the client libraries:


### Java

```java
private void runExample(GoogleAdsClient googleAdsClient, long customerId) {
  try (GoogleAdsServiceClient googleAdsServiceClient =
      googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
    String query = "SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id";
    // Constructs the SearchGoogleAdsStreamRequest.
    SearchGoogleAdsStreamRequest request =
        SearchGoogleAdsStreamRequest.newBuilder()
            .setCustomerId(Long.toString(customerId))
            .setQuery(query)
            .build();

    // Creates and issues a search Google Ads stream request that will retrieve all campaigns.
    ServerStream<SearchGoogleAdsStreamResponse> stream =
        googleAdsServiceClient.searchStreamCallable().call(request);

    // Iterates through and prints all of the results in the stream response.
    for (SearchGoogleAdsStreamResponse response : stream) {
      for (GoogleAdsRow googleAdsRow : response.getResultsList()) {
        System.out.printf(
            "Campaign with ID %d and name '%s' was found.%n",
            googleAdsRow.getCampaign().getId(), googleAdsRow.getCampaign().getName());
      }
    }
  }
}
      
```

### C#

```c#
public void Run(GoogleAdsClient client, long customerId)
{
    // Get the GoogleAdsService.
    GoogleAdsServiceClient googleAdsService = client.GetService(
        Services.V26.GoogleAdsService);

    // Create a query that will retrieve all campaigns.
    string query = @"SELECT
                    campaign.id,
                    campaign.name,
                    campaign.network_settings.target_content_network
                FROM campaign
                ORDER BY campaign.id";

    try
    {
        // Issue a search request.
        googleAdsService.SearchStream(customerId.ToString(), query,
            delegate (SearchGoogleAdsStreamResponse resp)
            {
                foreach (GoogleAdsRow googleAdsRow in resp.Results)
                {
                    Console.WriteLine("Campaign with ID {0} and name '{1}' was found.",
                        googleAdsRow.Campaign.Id, googleAdsRow.Campaign.Name);
                }
            }
        );
    }
    catch (GoogleAdsException e)
    {
        Console.WriteLine("Failure:");
        Console.WriteLine($"Message: {e.Message}");
        Console.WriteLine($"Failure: {e.Failure}");
        Console.WriteLine($"Request ID: {e.RequestId}");
        throw;
    }
}
      
```

### PHP

```php
public static function runExample(GoogleAdsClient $googleAdsClient, int $customerId)
{
    $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
    // Creates a query that retrieves all campaigns.
    $query = 'SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id';
    // Issues a search stream request.
    /** @var GoogleAdsServerStreamDecorator $stream */
    $stream = $googleAdsServiceClient->searchStream(
        SearchGoogleAdsStreamRequest::build($customerId, $query)
    );

    // Iterates over all rows in all messages and prints the requested field values for
    // the campaign in each row.
    foreach ($stream->iterateAllElements() as $googleAdsRow) {
        /** @var GoogleAdsRow $googleAdsRow */
        printf(
            "Campaign with ID %d and name '%s' was found.%s",
            $googleAdsRow->getCampaign()->getId(),
            $googleAdsRow->getCampaign()->getName(),
            PHP_EOL
        );
    }
}
      
```

### Python

```python
def main(client: GoogleAdsClient, customer_id: str) -> None:
    ga_service: GoogleAdsServiceClient = client.get_service("GoogleAdsService")

    query: str = """
        SELECT
          campaign.id,
          campaign.name
        FROM campaign
        ORDER BY campaign.id"""

    # Issues a search request using streaming.
    stream: Iterator[SearchGoogleAdsStreamResponse] = ga_service.search_stream(
        customer_id=customer_id, query=query
    )

    for batch in stream:
        rows: List[GoogleAdsRow] = batch.results
        for row in rows:
            print(
                f"Campaign with ID {row.campaign.id} and name "
                f'"{row.campaign.name}" was found.'
            )
      
```

### Ruby

```ruby
def get_campaigns(customer_id)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  responses = client.service.google_ads.search_stream(
    customer_id: customer_id,
    query: 'SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id',
  )

  responses.each do |response|
    response.results.each do |row|
      puts "Campaign with ID #{row.campaign.id} and name '#{row.campaign.name}' was found."
    end
  end
end
      
```

### Perl

```perl
sub get_campaigns {
  my ($api_client, $customer_id) = @_;

  # Create a search Google Ads stream request that will retrieve all campaigns.
  my $search_stream_request =
    Google::Ads::GoogleAds::V26::Services::GoogleAdsService::SearchGoogleAdsStreamRequest
    ->new({
      customerId => $customer_id,
      query      =>
        "SELECT campaign.id, campaign.name FROM campaign ORDER BY campaign.id"
    });

  # Get the GoogleAdsService.
  my $google_ads_service = $api_client->GoogleAdsService();

  my $search_stream_handler =
    Google::Ads::GoogleAds::Utils::SearchStreamHandler->new({
      service => $google_ads_service,
      request => $search_stream_request
    });

  # Issue a search request and process the stream response to print the requested
  # field values for the campaign in each row.
  $search_stream_handler->process_contents(
    sub {
      my $google_ads_row = shift;
      printf "Campaign with ID %d and name '%s' was found.\n",
        $google_ads_row->{campaign}{id}, $google_ads_row->{campaign}{name};
    });

  return 1;
}
      
```

### curl

> [!NOTE]
> **Note:** While a direct REST code sample for this step isn't provided here, you can achieve this using a manual REST request.   
>
> Refer to the Google Ads API REST interface documentation and the method-specific reference pages. You will need to construct the JSON payload based on the proto definitions.   
>
> Key Resources:
>
> - [Using REST](https://developers.google.com/google-ads/api/rest/overview.md.txt)
> - [REST Interface Structure](https://developers.google.com/google-ads/api/rest/design/overview.md.txt)
> - [JSON Field Mappings](https://developers.google.com/google-ads/api/rest/design/json-mappings.md.txt)
> - Consult the [REST API Reference](https://developers.google.com/google-ads/api/reference/rpc/latest/overview) for the specific service and method.

<br />