# G2 Product Search Scraper (`codingfrontend/g2-search-products-scraper`) Actor

Scrape software products, categories, and listings from G2.com with support for search, category, and direct product URL modes.

- **URL**: https://apify.com/codingfrontend/g2-search-products-scraper.md
- **Developed by:** [Coding Frontned](https://apify.com/codingfrontend) (community)
- **Categories:** E-commerce, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## G2 Product Search Scraper

Search G2's public product index by product name. The Actor returns only fields evidenced by the live JSON response: stable G2 product ID, product name, vendor name, favicon URL, match context, and HTTP provenance.

This Actor deliberately does not guess product slugs or claim pricing, ratings, features, reviews, or detail-page URLs that the public search response does not provide. It does not sign in or bypass CAPTCHA, WAF, login, rate, device, paywall, or geographic controls.

### Input

| Field | Default | Limits | Purpose |
|---|---:|---:|---|
| `queries` | `["slack"]` | 1–5 strings, 1–100 characters | Product-name searches. |
| `searchQuery` | — | 1–100 characters | Optional backward-compatible single query combined with `queries`. |
| `maxItems` | `20` | 1–100 | Global unique-product cap. |
| `maxPagesPerQuery` | `1` | 1–3 | Per-query pagination safety cap. |
| `pageSize` | `50` | 1–100 | Requested page size; G2 may return a different bounded count. |
| `requestDelayMs` | `300` | 250–10,000 | Spacing between consecutive requests. |
| `requestTimeoutMs` | `12000` | 5,000–30,000 | Per-request timeout. |
| `maxAttempts` | `2` | 1–2 | Attempts for transient network, server, or invalid-response failures. |

Example:

```json
{
  "queries": ["slack", "crm"],
  "maxItems": 20,
  "maxPagesPerQuery": 1
}
```

The schema and runtime reject unknown fields, numeric strings, empty queries, duplicate queries after case normalization, and excessive workloads.

### Output

Each product row contains:

- `recordId` and integer `productId` from G2
- `productName`, optional `vendorName`, and optional public `faviconUrl`
- `matchedQueries`, first query, result position, and response page
- exact source API URL, public search URL, response count, HTTP/content/byte/attempt evidence
- source domain, endpoint path, extraction method, request identity, and timestamp

```json
{
  "recordType": "g2Product",
  "status": "success",
  "dataAvailable": true,
  "found": true,
  "recordId": "g2:154880",
  "productId": 154880,
  "productName": "Bored on Slack",
  "vendorName": "SuperGaming",
  "matchedQueries": ["slack"],
  "queryResultPosition": 1,
  "httpStatus": 200,
  "sourceDomain": "www.g2.com",
  "provenance": "public_g2_product_index"
}
```

Products appearing under multiple queries are deduplicated by G2 product ID and retain every matched query. Optional blank values are omitted instead of emitted as null placeholders.

If a request fails or hits an access boundary, the Actor writes one typed diagnostic row and fails without publishing partial product records. If all queries return no matches, it similarly records `NO_RESULTS` and fails. The named `OUTPUT` key-value record summarizes status, items, unique IDs, query progress, requests, and duration.

### Cost and limits

The Actor uses direct sequential HTTPS requests and no browser or proxy. Cost depends mainly on request count, compute, and storage. The global result cap can end the run before later queries are requested; limits are caps, not guaranteed quotas.

### Local development

```text
npm ci
npm test
apify validate-schema
apify run --purge --input-file qa-inputs/local-single.json
npm run validate -- storage/datasets/default
```

The semantic validator checks every declared type, required evidence, product-ID uniqueness, success status, and absence of diagnostics.

### Responsible use

Only data returned by G2's public product lookup is collected. Review G2's terms and applicable law. The Actor is an independent adapter and does not represent G2. For support, include query, HTTP status, and diagnostic code without sharing credentials.

# Actor input Schema

## `queries` (type: `array`):

One to five product-name queries.

## `searchQuery` (type: `string`):

Optional backward-compatible single query combined with queries.

## `maxItems` (type: `integer`):

Global unique-product cap across all queries.

## `maxPagesPerQuery` (type: `integer`):

Pagination safety cap for each query.

## `pageSize` (type: `integer`):

Requested product count per public index page.

## `requestDelayMs` (type: `integer`):

Minimum spacing between consecutive public requests.

## `requestTimeoutMs` (type: `integer`):

Per-request timeout.

## `maxAttempts` (type: `integer`):

One or two attempts for transient network, server, or invalid-response failures; access boundaries are not retried.

## Actor input object example

```json
{
  "queries": [
    "slack"
  ],
  "maxItems": 20,
  "maxPagesPerQuery": 1,
  "pageSize": 50,
  "requestDelayMs": 300,
  "requestTimeoutMs": 12000,
  "maxAttempts": 2
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing public product search records or one diagnostic row.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "slack"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("codingfrontend/g2-search-products-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "queries": ["slack"] }

# Run the Actor and wait for it to finish
run = client.actor("codingfrontend/g2-search-products-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "slack"
  ]
}' |
apify call codingfrontend/g2-search-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,codingfrontend/g2-search-products-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HptHYuTNGft7DLTJD/builds/0EhUvYTJtM36BqOYm/openapi.json
