From a5f8fda70cba4f20aae0e267e6225528dd220c6f Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Wed, 3 Sep 2025 17:22:48 +0200 Subject: [PATCH 01/21] docs: PPE refactor - first draft --- package-lock.json | 2 +- .../{monetize.mdx => _old_monetize.mdx} | 4 +- .../actors/publishing/monetize/index.mdx | 118 ++++++ .../publishing/monetize/pay_per_event.mdx | 342 ++++++++++++++++++ .../publishing/monetize/pay_per_result.mdx | 109 ++++++ .../actors/publishing/monetize/rental.mdx | 53 +++ 6 files changed, 625 insertions(+), 3 deletions(-) rename sources/platform/actors/publishing/{monetize.mdx => _old_monetize.mdx} (99%) create mode 100644 sources/platform/actors/publishing/monetize/index.mdx create mode 100644 sources/platform/actors/publishing/monetize/pay_per_event.mdx create mode 100644 sources/platform/actors/publishing/monetize/pay_per_result.mdx create mode 100644 sources/platform/actors/publishing/monetize/rental.mdx diff --git a/package-lock.json b/package-lock.json index 2a62aceead..cf69dbbf5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,7 +75,7 @@ }, "apify-docs-theme": { "name": "@apify/docs-theme", - "version": "1.0.208", + "version": "1.0.209", "license": "ISC", "dependencies": { "@apify/docs-search-modal": "^1.2.2", diff --git a/sources/platform/actors/publishing/monetize.mdx b/sources/platform/actors/publishing/_old_monetize.mdx similarity index 99% rename from sources/platform/actors/publishing/monetize.mdx rename to sources/platform/actors/publishing/_old_monetize.mdx index 1e669c6e46..4585f33431 100644 --- a/sources/platform/actors/publishing/monetize.mdx +++ b/sources/platform/actors/publishing/_old_monetize.mdx @@ -1,4 +1,4 @@ ---- +{/* --- title: Monetize your Actor description: Learn how you can monetize your web scraping and automation projects by publishing Actors to users in Apify Store. slug: /actors/publishing/monetize @@ -282,4 +282,4 @@ Create serach-engine-optimized descriptions and README files to improve search e Remember to tag Apify in your social media posts for additional exposure. Effective promotion can significantly impact your Actor's success, differentiating between those with many paid users and those with few to none. Learn more about promoting your Actor in the [Apify's marketing playbook](/academy/actor-marketing-playbook). - + */} diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx new file mode 100644 index 0000000000..e4d6603434 --- /dev/null +++ b/sources/platform/actors/publishing/monetize/index.mdx @@ -0,0 +1,118 @@ +--- +title: Monetize your Actor +description: Learn how you can monetize your web scraping and automation projects by publishing Actors to users in Apify Store. +slug: /actors/publishing/monetize +sidebar_position: 2 +--- + +**Learn how you can monetize your web scraping and automation projects by publishing Actors to users in Apify Store.** + +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Apify Store allows you to monetize your web scraping, automation and AI Agent projects by publishing them as paid Actors. This guide explains the available pricing models and how to get started. + +## Pricing models + +Actors in Apify Store can be published under one of the following pricing models: + +1. **Free**: Users can run the Actor without any additional charges beyond the platform usage costs generated by the Actor. +2. **Rental**: Users pay for the platform usage costs. However, after a trial period, they need to pay a flat monthly fee to the developer to continue using the Actor. +3. **Pay per result (PPR)**: Users don't pay for the platform usage costs. Instead, they pay the developer based on the number of results produced by the Actor. +4. **Pay per event (PPE)**: Users don't pay for the platform usage cost the Actor generates. Instead, they pay based on specific events that are programmatically triggered from the Actor's source code. These events are defined by the developer and can include actions such as generating a single result or starting an Actor. + +For a detailed comparison of pricing models from the perspective of your users, refer to [Actors in Store](/platform/actors/running/actors-in-store) page. + +## Key benefits + +The following table compares the two main pricing models available for monetizing your Actors: + +| Feature/Category | Rental pricing | Pay-per-event/result | +|------------------|----------------|---------------------| +| Revenue scalability | Capped at monthly fee | Unlimited, scales with usage | +| AI/MCP compatibility | ❌ Not compatible | ✅ Fully compatible | +| User cost predictability | Confusing (rental + usage) | Clear, transparent pricing | +| Tiered pricing support | ❌ Single price only | ✅ Store discounts available | +| Marketing boost* | Standard visibility | Priority store placement | +| Commission opportunities | Standard 20% | Promotional 0% periods | + +## Setting up monetization + +Navigate to your [Actor page](https://console.apify.com/actors?tab=my) in Apify Console, choose the Actor that you want to monetize, and select the Publication tab. +![Monetization section](../images/monetization-section.png) +Open the Monetization section and complete your billing and payment details. +![Set up monetization](../images/monetize_actor_set_up_monetization.png) +Choose the pricing model for your Actor. +![Monetization wizard](../images/monetization_wizard.png) +Follow the monetization wizard to configure your pricing model. + + +![rental moentization wizard](../images/rental-wizard.png) + + +![ppr moentization wizard](../images/ppr-wizard.png) + + +![ppe moentization wizard](../images/ppe-wizard.png) + + + +## Changing monetization + +You can change the monetization setting of your Actor by using the same wizard as for the setup in the **Monetization** section of your Actor's **Publication** tab. Any changes made to an already published Actor will take _14 days_ to come into effect, so that the users of your Actor have time to prepare. + +:::important Frequency of monetization adjustments + +Be aware that you can change the monetization setting of each Actor only once per month. For further information and guidelines, please refer to our [Terms & Conditions](https://apify.com/store-terms-and-conditions) + +::: + +## Monthly payouts and analytics + +Payout invoices are automatically generated on the 11th of each month, summarizing the profits from all your Actors for the previous month. +In accordance with our [Terms & Conditions](https://apify.com/store-terms-and-conditions), only funds from legitimate users who have already paid are included in the payout invoice. + +:::note How negative profits are handled + +If your PPR or PPE Actor's price doesn't cover its monthly platform usage costs, it will have a negative profit. When this occurs, we automatically set that Actor's profit to $0 for the month. This ensures a single Actor's loss never reduces your total payout. + +::: + +You have 3 days to review your payout invoice in the **Development >Insights > Payout** section. During this period, you can either approve the invoice or request a revision, which we will process promptly. +If no action is taken, the payout will be automatically approved on the 14th, with funds disbursed shortly after. Payouts require meeting minimum thresholds of either: + +- $20 for PayPal +- $100 for other payout methods + +If the monthly profit does not meet these thresholds, as per our [Terms & Conditions](https://apify.com/store-terms-and-conditions), the funds will roll over to the next month until the threshold is reached. + +## Actor analytics + +Monitor your Actors' performance through the [Actor Analytics](https://console.apify.com/actors/insights/analytics) dashboard under **Development > Insights > Analytics**. + +The analytics dashboard allows you to select specific Actors and view key metrics aggregated across all user runs: + +- Revenue, costs and profit trends over time +- User growth metrics (both paid and free users) +- Cost per 1,000 results to optimize pricing +- Run success rate statistics +- User acquisition funnel analytics +- Shared debug runs from users + +All metrics can be exported as JSON for custom analysis and reporting. + +## Promoting your Actor + +Create serach-engine-optimized descriptions and README files to improve search engine visibility. Share your Actor on multiple channels: + +- Post on Reddit, Quora, and social media platforms +- Create tutorial videos demonstrating key features +- Publish articles about your Actor on relevant websites +- Consider creating a product showcase on platforms like Product Hunt + +Remember to tag Apify in your social media posts for additional exposure. Effective promotion can significantly impact your Actor's success, differentiating between those with many paid users and those with few to none. + +Learn more about promoting your Actor in the [Apify's marketing playbook](/academy/actor-marketing-playbook). + diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx new file mode 100644 index 0000000000..98d42deca2 --- /dev/null +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -0,0 +1,342 @@ +--- +title: Pay per event (PPE) +description: TBD +slug: /actors/publishing/monetize/pay-per-event +sidebar_position: 3 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +The pay-per-event pricing model offers a flexible monetization option for Actors on Apify Store. Unlike pay per result, PPE allows you to charge users based on specific events triggered programmatically by your Actor's code. + +PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor by calling the [PPE charging API](/api/v2/post-charge-run), or through [JS](/sdk/js/reference/class/Actor#charge)/[Python](/sdk/python/reference/class/Actor#charge) SDK Common events include Actor start, dataset item creation, and external API calls. + +## How is profit computed + +Your profit is calculated from the mentioned formula: + +`profit = (0.8 * revenue) - platform costs` + +where: + +- _Revenue_: The amount charged for events via the PPE charging API or through JS/Python SDK. You receive 80% of this revenue. +- _Platform costs_: The underlying platform usage costs for running the Actor, calculated in the same way as for PPR. For more details, visit the [Computing your costs for PPE and PPR Actors](#computing-your-costs-for-ppe-and-ppr-actors) section. + +Only revenue and cost for Apify customers on paid plans are taken into consideration when computing your profit. Users on free plans are not reflected there. + +:::note Negative profit isolation + +An Actor's negative net profit does not affect the positive profit of another Actor. For aggregation purposes, any Actor with a negative net profit is considered to have a profit of $0. + +- _Previously:_ `Total Profit = (-$90) + $100 = $10` +- _Now:_ `Total Profit = $0 + $100 = $100` + +::: + +## How to set pricing for pay-per-event Actors + +1. _Understand your costs_: Analyze resource usage (e.g CPU, memory, proxies, external APIs) and identify cost drivers +1. _Define clear events_: break your Actor's functionality into measurable, chargeable events. +1. _Common use cases_: + 1. _For scraping_: combine Actor start and dataset items pricing to reflect setup and per-result cost. + 1. _Beyond scraping_: Account for integrations with external systems or external API calls. +1. _External API costs_: Account for additional processing costs. +1. _Test your pricing_: Run your Actor and analyze cost-effectiveness using a special dataset. +1. _Communicate value_: Ensure pricing reflects the value provided and is competitive. + +## Best practices for pay-per-event Actors + +Use our SDKs (JS and, Python or use [`apify actor charge`](/cli/docs/next/reference#apify-actor-charge-eventname) when using our Apify CLI) to simplify PPE implementation into your Actor. This tool can handle pricing, usage tracking, idempotency keys, API errors, and, event charging via an API. + +You can also choose not to use it, but then you must handle API integration and possible edge cases manually. + +### Set memory limits + +Set memory limits using `minMemoryMbytes` and `maxMemoryMbytes` in your [`actor.json`](https://docs.apify.com/platform/actors/development/actor-definition/actor-json) file to control platform usage costs. + +```json +{ + "actorSpecification": 1, + "name": "name-of-my-scraper", + "version": "0.0", + "minMemoryMbytes": 256, + "maxMemoryMbytes": 4096, +} +``` + +### Charge for "Actor start" + +Charge for "Actor start" to prevent users from running your Actor for free. + +```typescript +import { Actor } from 'apify'; + +const chargeForActorStart = async () => { + const chargingManager = Actor.getChargingManager(); + + // Don't charge the "Actor start" event again after Actor migration + if (chargingManager.getChargedEventCount("actor-start") === 0) { + await Actor.charge({ + "eventName": "actor-start", + }); + } +} + +await Actor.init(); + +const main = async () => { + await chargeForActorStart(); + + // Continue with the Actor's main logic +}; + +await main(); + +await Actor.exit(); +``` + +:::note Actor migrations and charging + +Actors can migrate between servers during execution, which restarts the process and clears memory. When using PPE charging, avoid charging the start event multiple times after a migration by checking your charging state. +::: + +### Charge for invalid input + +Charge for invalid input or empty search to prevent users from running your Actor for free. + +```typescript +import { Actor } from 'apify'; +import { Input } from './types'; + +const parseInput = async (input: Input) => { + if (!input.searchStringsArray && !input.startUrls && !input.allPlacesNoSearchAction) { + await Actor.charge({ + eventName: "invalid-input", + }); + + throw await Actor.fail('INVALID INPUT: You must provide either search terms, start URLs, or allPlacesNoSearchAction!'); + } + + return input; +}; + +await Actor.init(); + +const main = async () => { + const input = await Actor.getInput(); + const parsedInput = await parseInput(input); + + // Continue with the Actor's main logic +}; + +await main(); + +await Actor.exit(); +``` + +### Respect user spending limits + +Finish the Actor run once charging reaches user-configured Maximum cost per run. Apify SDKs (JS and Python) return ChargeResult that helps determine when to finish. + +```typescript +import { Actor } from 'apify'; + +const MAX_COST = Number(process.env.ACTOR_MAX_TOTAL_CHARGE_USD); + +const chargForApiCall = async () => { + const chargeResult = await Actor.charge({ + eventName: "api-call", + }); + + return chargeResult; +}; + +await Actor.init(); + +const main = async () => { + // actual API call + + const chargeResult = await chargForApiCall(); + + if (chargeResult.totalCost >= MAX_COST) { + await Actor.exit(); + } + + // continue with the Actor's main logic +}; + +await main(); + +await Actor.exit(); +``` + +### Use idempotency keys to prevent double charges + +If you're not using the Apify SDKs (JS/Python), you need to handle idempotency (ensuring the same operation produces the same result when called multiple times) manually to prevent charging the same event multiple times. + +### Keep pricing simple with fewer events + +Try to limit the number of events. Fewer events make it easier for users to understand your pricing and predict their costs. + +### Make events produce tangible results + +Try to make your event have tangible artifacts that users can see and understand (this might not be possible when using external APIs). Each charged event should produce something concrete in the user's dataset. + +Good examples: + +- **"scraped-product"** event: Each charge adds one product record to the dataset +- **"processed-image"** event: Each charge adds one processed image to the dataset +- **"extracted-review"** event: Each charge adds one review to the dataset + +Avoid charging for: + +- Internal processing steps that don't produce visible results +- API calls that don't generate user-visible data +- Setup or configuration steps + +This helps users understand exactly what they're paying for and builds trust in your pricing model. + +## PPE event names + +To implement pay-per-event pricing, you need to define specific events in your Actor code. You can retrieve the list of available pricing event names using the [Get Actor](https://apify.com/docs/api/v2/act-get) API endpoint. + +## How to attract larger customers of PPE and PPR Actors + +Each user running your PPE or PPR Actor belongs to a discount tier: + +- _FREE_ +- _BRONZE_ +- _SILVER_ +- _GOLD_ + + +You can define different prices for different tiers. +While optional, we recommend offering progressively lower prices for higher discount tiers. This approach can significantly improve attractiveness of your Actor to large enterprise customers who may spend thousands or tens of thousands of dollars on it. + +Your platform costs are also lower for these higher tier, which helps maintain healthy profit margins. This is further detailed in the [Computing your costs for PPE and PPR Actors](#computing-your-costs-for-ppe-and-ppr-actors) section. + +By default, we advise against setting excessively high prices for _FREE_ tier users, as this can limit the ability to evaluate your Actor thoroughly. However, in certain situations, such as protecting your Actor from fraudulent activity or excessive use of your internal APIs, a higher price for _FREE_ tier users might be justified. + +During an Actor run, you can identify the user's discount tier through Actor run environment variables or by querying user data via the Apify API. This capability allows you to offer premium features or differentiated service levels to users in higher discount tiers. + +In addition to the standard tiers, Apify provides further tiers specifically for enterprise customers, including _PLATINUM_ and _DIAMOND_ tiers. If you are interested in offering enterprise-level services and attracting major clients, please contact us. + +## Computing your costs for PPE and PPR Actors + +For both PPE and PPR Actors, profit is computed using the formula `(0.8 * revenue) - costs`. In this section, we'll explain how the `costs` component is calculated. + +When paying users run your Actor, it generates platform usage in the form of compute units, data traffic, API operations etc. This usage determines the `costs` in the profit formula above. + +:::note _FREE_ tier usage + +Platform usage by _FREE_ tier users is covered by Apify and does not contribute to your costs. + +::: + +To calculate your costs in dollars for a specific run by paying user, multiply the unit cost of each service by the quantity consumed. For example, if a _BRONZE_ tier user run uses 10 compute units (CUs) at $0.4/CU, your cost would be $4. + +As highlighted in the [How to attract larger customers of PPE and PPR Actors](#how-to-attract-larger-customers-of-ppe-and-ppr-actors) section, if your Actor uses tiered pricing, the user's discount tier determines the unit costs applied to their runs. Your costs are lower for higher tiers, enabling you to offer more competitive pricing to these customers, while sustaining healthy profit margins. + +The following table summarizes the platform unit costs used for your cost computation across different discount tiers. + +| Service | Price is per | _FREE_ | _BRONZE_ | _SILVER_ | _GOLD_ | +|:-------------------------------|:--------------|--------:|---------:|---------:|--------:| +| Compute unit | CU | $0.4 | $0.4 | $0.3 | $0.25 | +| Residential proxies | GB | $8 | $8 | $7.5 | $7 | +| SERPs proxy | 1,000 SERPs | $2.5 | $2.5 | $2 | $1.7 | +| Data transfer - external | GB | $0.2 | $0.2 | $0.19 | $0.18 | +| Data transfer - internal | GB | $0.05 | $0.05 | $0.045 | $0.04 | +| Dataset - reads | 1,000 reads | $0.0004 | $0.0004 | $0.00036 | $0.00032| +| Dataset - writes | 1,000 writes | $0.005 | $0.005 | $0.0045 | $0.004 | +| Key-value store - reads | 1,000 reads | $0.005 | $0.005 | $0.0045 | $0.004 | +| Key-value store - writes | 1,000 writes | $0.05 | $0.05 | $0.045 | $0.04 | +| Key-value store - lists | 1,000 lists | $0.05 | $0.05 | $0.045 | $0.04 | +| Request queue - reads | 1,000 reads | $0.004 | $0.004 | $0.0036 | $0.0032 | +| Request queue - writes | 1,000 writes | $0.02 | $0.02 | $0.018 | $0.016 | + +If you decide not to offer tiered discounts on your Actor, the unit prices for _FREE_ tier apply. To offer enterprise level services and unlock even cheaper unit prices for enterprise customers, please reach out to us. + +:::note Cost of PPE Actors in Standby mode + +When you monetize your Actor in Standby mode using pay per event mode only, you are not responsible for covering platform usage costs of your users' runs. + +::: + +## Setting up monetization + +Navigate to your [Actor page](https://console.apify.com/actors?tab=my) in Apify Console, choose the Actor that you want to monetize, and select the Publication tab. +![Monetization section](../images/monetization-section.png) +Open the Monetization section and complete your billing and payment details. +![Set up monetization](../images/monetize_actor_set_up_monetization.png) +Choose the pricing model for your Actor. +![Monetization wizard](../images/monetization_wizard.png) +Follow the monetization wizard to configure your pricing model. + + +![rental moentization wizard](../images/rental-wizard.png) + + +![ppr moentization wizard](../images/ppr-wizard.png) + + +![ppe moentization wizard](../images/ppe-wizard.png) + + + +## Changing monetization + +You can change the monetization setting of your Actor by using the same wizard as for the setup in the **Monetization** section of your Actor's **Publication** tab. Any changes made to an already published Actor will take _14 days_ to come into effect, so that the users of your Actor have time to prepare. + +:::important Frequency of monetization adjustments + +Be aware that you can change the monetization setting of each Actor only once per month. For further information and guidelines, please refer to our [Terms & Conditions](https://apify.com/store-terms-and-conditions) + +::: + +## Monthly payouts and analytics + +Payout invoices are automatically generated on the 11th of each month, summarizing the profits from all your Actors for the previous month. +In accordance with our [Terms & Conditions](https://apify.com/store-terms-and-conditions), only funds from legitimate users who have already paid are included in the payout invoice. + +:::note How negative profits are handled + +If your PPR or PPE Actor's price doesn't cover its monthly platform usage costs, it will have a negative profit. When this occurs, we automatically set that Actor's profit to $0 for the month. This ensures a single Actor's loss never reduces your total payout. + +::: + +You have 3 days to review your payout invoice in the **Development >Insights > Payout** section. During this period, you can either approve the invoice or request a revision, which we will process promptly. +If no action is taken, the payout will be automatically approved on the 14th, with funds disbursed shortly after. Payouts require meeting minimum thresholds of either: + +- $20 for PayPal +- $100 for other payout methods + +If the monthly profit does not meet these thresholds, as per our [Terms & Conditions](https://apify.com/store-terms-and-conditions), the funds will roll over to the next month until the threshold is reached. + +## Actor analytics + +Monitor your Actors' performance through the [Actor Analytics](https://console.apify.com/actors/insights/analytics) dashboard under **Development > Insights > Analytics**. + +The analytics dashboard allows you to select specific Actors and view key metrics aggregated across all user runs: + +- Revenue, costs and profit trends over time +- User growth metrics (both paid and free users) +- Cost per 1,000 results to optimize pricing +- Run success rate statistics +- User acquisition funnel analytics +- Shared debug runs from users + +All metrics can be exported as JSON for custom analysis and reporting. + +## Promoting your Actor + +Create serach-engine-optimized descriptions and README files to improve search engine visibility. Share your Actor on multiple channels: + +- Post on Reddit, Quora, and social media platforms +- Create tutorial videos demonstrating key features +- Publish articles about your Actor on relevant websites +- Consider creating a product showcase on platforms like Product Hunt + +Remember to tag Apify in your social media posts for additional exposure. Effective promotion can significantly impact your Actor's success, differentiating between those with many paid users and those with few to none. + +Learn more about promoting your Actor in the [Apify's marketing playbook](/academy/actor-marketing-playbook). \ No newline at end of file diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx new file mode 100644 index 0000000000..96bafe004c --- /dev/null +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -0,0 +1,109 @@ +--- +title: Pay per result (PPR) +description: TBD +slug: /actors/publishing/monetize/pay-per-result +sidebar_position: 2 +--- + +In this model, you set a price per 1,000 results. Users are charged based on the number of results your Actor produces and stores in the run's default dataset. Your profit is calculated as 80% of the revenue minus platform usage costs. + +The details on how your cost is computed can be found in [Example of a pay-per-result pricing model](#example-of-a-pay-per-result-pricing-model). + +## How is profit computed + +Your profit is calculated from the mentioned formula: + +`profit = (0.8 * revenue) - platform costs` + +where: + +- _Revenue_: The amount charged for results via the PPR pricing API or through JS/Python SDK. You receive 80% of this revenue. +- _Platform costs_: The underlying platform usage costs for running the Actor, calculated in the same way as for PPE. For more details, visit the [Example of a pay-per-result pricing model](#example-of-a-pay-per-result-pricing-model) section. + +Only revenue and cost for Apify customers on paid plans are taken into consideration when computing your profit. Users on free plans are not reflected there. + +## Best practices for pay-per-result Actors + +To ensure profitability, check the following best practices. + +### Set memory limits + +Set memory limits using `minMemoryMbytes` and `maxMemoryMbytes` in your [`actor.json`](https://docs.apify.com/platform/actors/development/actor-definition/actor-json) file to control platform usage costs. + +```json +{ + "actorSpecification": 1, + "name": "name-of-my-scraper", + "version": "0.0", + "minMemoryMbytes": 256, + "maxMemoryMbytes": 4096, +} +``` + +### Implement the `ACTOR_MAX_PAID_DATASET_ITEMS` check + +This check prevents your Actor from generating more results than the user has paid for, protecting both you and your users from unexpected costs. + +The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for paid-per-result Actors. Do not exceed this limit. + +```typescript +const MAX_ITEMS = Number(process.env.ACTOR_MAX_PAID_DATASET_ITEMS); +let pushedItemCount = 0; + +export const pushDataMaxAware = async (data: Parameters[0]) => { + // rest of the code... + + const dataAsArray = Array.isArray(data) ? data : [data]; + const dataToPush = dataAsArray.slice(0, MAX_ITEMS - pushedItemCount); + + if (dataToPush.length) { + // We have to update the state before 'await' to avoid race conditions + pushedItemCount += dataToPush.length; + await Actor.pushData(dataToPush); + } + + // rest of the code... +} +``` + +You can find the whole code of implementing this check in this [example](https://github.com/metalwarrior665/max-paid-items-example/blob/master/src/push-data.ts). + +### Test your Actor + +Test your Actor with various result volumes to determine optimal pricing. Start with minimal datasets (1-100 results) to understand your base costs and ensure the Actor works correctly with small inputs. Then test with typical usage volumes (1,000-10,000 results) to simulate real-world scenarios and identify any performance bottlenecks. + +Throughout all testing, monitor platform usage costs for each test run to calculate the true cost per result. This cost analysis is crucial for setting profitable pricing that covers your expenses while remaining competitive in the market. + +### Push at least one "error item" to the dataset + +In PPR Actors, users are only charged when your Actor produces results in the dataset. If your Actor encounters invalid input or finds no results, it should still push at least one item to the dataset to ensure the user is charged for the attempt. + +Why this matters: + +- **Prevents free usage**: Without pushing any items, users could run your Actor repeatedly with invalid inputs without being charged +- **Ensures fair billing**: Users should pay for the processing attempt, even if no valid results are found +- **Maintains profitability**: Every run should generate some revenue to cover your platform costs + +Example scenarios: + +- **User provides invalid search terms**: Push an error item explaining the issue +- **Target website returns no results**: Push an item indicating "No results found" +- **Input validation fails**: Push an item with validation error details + +This ensures that every run generates at least one result, guaranteeing that users are charged appropriately for using your Actor. + +## Example of a pay-per-result pricing model + +You make your Actor pay-per-result and set the price to be **$1/1,000 results**. During the first month, three users use your Actor: + +- **User 1** (paid plan): Gets 50,000 results, costing them $50 +- **User 2** (paid plan): Gets 20,000 results, costing them $20 +- **User 3** (free plan): Gets 5,000 results, costing them $0 + +Let's say the underlying platform usage for the first user is $5, for the second $2, and for the third $0.5. + +Your profit is computed only from the first two users, since they are on Apify paid plans. The revenue breakdown is: + +- **Total revenue**: $50 + $20 = $70 +- **Total underlying cost**: $5 + $2 = $7 +- **Your profit**: 80% of revenue minus costs = 0.8 × $70 - $7 = **$49** diff --git a/sources/platform/actors/publishing/monetize/rental.mdx b/sources/platform/actors/publishing/monetize/rental.mdx new file mode 100644 index 0000000000..d174284df2 --- /dev/null +++ b/sources/platform/actors/publishing/monetize/rental.mdx @@ -0,0 +1,53 @@ +--- +title: Rental pricing model +description: TBD +slug: /actors/publishing/monetize/rental +sidebar_position: 1 +--- + +With the rental model, you can specify a free trial period and a monthly rental price. After the trial, users with an [Apify paid plan](https://apify.com/pricing) can continue using your Actor by paying the monthly fee. You can receive 80% of the total rental fees collected each month. + +## How is profit computed + +Your profit is calculated from the mentioned formula: + +`profit = 0.8 × rental fees` + +where: + +- _Rental fees_: The monthly rental fee set by the developer (for example, $30/month). + +Only revenue and cost for Apify customers on paid plans are taken into consideration when computing your profit. Users on free plans are not reflected there. + +## Disadvantages of the rental pricing model + +### User cost confusion + +Users consistently report confusion about rental pricing because they pay both the monthly rental fee AND platform usage costs. A user might see an Actor priced at $20/month, only to discover their actual costs are $35-50 depending on usage. This can create confusion about total costs and make budgeting more difficult. + +### Limited revenue scalability + +The rental model, while easy to set up, is less profitable because its pricing doesn't scale with usage. Your revenue is capped at the monthly fee regardless of how much value users extract from your Actor. + +### AI compatibility limitations + +The growing limitation is AI compatibility. Apify's MCP server explicitly excludes rental Actors from search results, making them invisible to AI systems that dynamically select and execute tools. This significantly reduces your Actor's discoverability in AI workflows. + +## Consider pay-per-result or pay-per-event pricing models + +Based on the reasons mentioned in [Disadvantages of the rental pricing model](#disadvantages-of-the-rental-pricing-model), we recommend using the [pay-per-result](/platform/actors/publishing/monetize/pay-per-result) or [pay-per-event](/platform/actors/publishing/monetize/pay-per-event) models instead. + +## Example of a rental pricing model + +You make your Actor rental with **7-day free trial** and then **$30/month**. During the first calendar month, three users start to use your Actor: + +- **User 1** (paid plan): Starts free trial on the 15th +- **User 2** (paid plan): Starts free trial on the 25th +- **User 3** (free plan): Starts free trial on the 20th + +The first user pays their first rent 7 days after the free trial, i.e., on the 22nd of the month. The second user only starts paying the rent next month. The third user is on the Apify free plan, so after the free trial ends on the 27th of the month, they are not charged and cannot use the Actor further until they get a paid plan. + +Your profit is computed only from the first user, since they are the only one who paid during this month. The revenue breakdown is: + +- **Total revenue**: $30 (from User 1 only) +- **Your profit**: 80% of revenue = 0.8 × $30 = **$24** From bf43145091dd2da14347de8303567f0cfc08347b Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Thu, 4 Sep 2025 09:08:46 +0200 Subject: [PATCH 02/21] docs: PPE pricing improvements --- .../actors/publishing/_old_monetize.mdx | 285 ----------------- .../actors/publishing/monetize/index.mdx | 19 +- .../publishing/monetize/pay_per_event.mdx | 286 +++++++++--------- .../publishing/monetize/pay_per_result.mdx | 83 +++-- .../publishing/monetize/pricing_and_costs.mdx | 72 +++++ .../actors/publishing/monetize/rental.mdx | 6 +- 6 files changed, 288 insertions(+), 463 deletions(-) delete mode 100644 sources/platform/actors/publishing/_old_monetize.mdx create mode 100644 sources/platform/actors/publishing/monetize/pricing_and_costs.mdx diff --git a/sources/platform/actors/publishing/_old_monetize.mdx b/sources/platform/actors/publishing/_old_monetize.mdx deleted file mode 100644 index 4585f33431..0000000000 --- a/sources/platform/actors/publishing/_old_monetize.mdx +++ /dev/null @@ -1,285 +0,0 @@ -{/* --- -title: Monetize your Actor -description: Learn how you can monetize your web scraping and automation projects by publishing Actors to users in Apify Store. -slug: /actors/publishing/monetize -sidebar_position: 2 ---- - -**Learn how you can monetize your web scraping and automation projects by publishing Actors to users in Apify Store.** - ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -Apify Store allows you to monetize your web scraping, automation and AI Agent projects by publishing them as paid Actors. This guide explains the available pricing models and how to get started. - -## Pricing models - -Actors in Apify Store can be published under one of the following pricing models: - -1. **Free**: Users can run the Actor without any additional charges beyond the platform usage costs generated by the Actor. -2. **Rental**: Users pay for the platform usage costs. However, after a trial period, they need to pay a flat monthly fee to the developer to continue using the Actor. -3. **Pay per result (PPR)**: Users don't pay for the platform usage costs. Instead, they pay the developer based on the number of results produced by the Actor. -4. **Pay per event (PPE)**: Users don't pay for the platform usage cost the Actor generates. Instead, they pay based on specific events that are programmatically triggered from the Actor's source code. These events are defined by the developer and can include actions such as generating a single result or starting an Actor. - -For a detailed comparison of pricing models from the perspective of your users, refer to [Actors in Store](/platform/actors/running/actors-in-store) page. - -### Rental pricing model - -With the rental model, you can specify a free trial period and a monthly rental price. After the trial, users with an [Apify paid plan](https://apify.com/pricing) can continue using your Actor by paying the monthly fee. You can receive 80% of the total rental fees collected each month. - -
- Example - rental pricing model - -You make your Actor rental with 7-day free trial and then $30/month. During the first calendar month, three users start to use your Actor: - -1. First user, on the Apify paid plan, starts the free trial on the 15th -1. Second user, on the Apify paid plan, starts the free trial on the 25th -1. Third user, on the Apify free plan, starts the free trial on the 20th - -The first user pays their first rent 7 days after the free trial, i.e., on the 22nd of the month. The second user only starts paying the rent next month. The third user is on the Apify free plan, so after the free trial ends on the 27th of the month, they are not charged and cannot use the Actor further until they get a paid plan. Your profit is computed only from the first user. They were charged $30, so 80% of this goes to you, i.e., _0.8 * 30 = $24_. -
- -:::note Rental Actors in AI workflows - -The rental model, while easy to set up, is less profitable because its pricing doesn't scale with usage. It is also impractical for AI agent applications and MCP servers, because of the upfront commitment of rental Actors. - -For Actors intended for AI workflows, use the [pay-per-result](/platform/actors/publishing/monetize#pay-per-result-ppr-pricing-model) or [pay-per-event](/platform/actors/publishing/monetize#pay-per-event-ppe-pricing-model) models instead. - -::: - -### Pay-per-result (PPR) pricing model - -In this model, you set a price per 1,000 results. Users are charged based on the number of results your Actor produces and stores in the run's default dataset. Your profit is calculated as 80% of the revenue minus platform usage costs. The formula is: - -`(0.8 * revenue) - costs = profit` - - -Only revenue and cost for Apify customers on paid plans are taken into consideration when computing your profit. Users on free plans are not reflected there. - -The details on how your cost is computed can be found in [Computing your costs for PPE and PPR Actors](#computing-your-costs-for-ppe-and-ppr-actors). - -
-Example - pay-per-result pricing model - -You make your Actor pay-per-result and set the price to be $1/1,000 results. During the first month, two users on Apify paid plans use your Actor to get 50,000 and 20,000 results, costing them $50 and $20, respectively. Let's say the underlying platform usage for the first user is $5 and for the second $2. A third user, this time on an Apify free plan, uses the Actor to get 5,000 results, with underlying platform usage of $0.5. - -Your profit is computed only from the first two users, since they are on Apify paid plans. The revenue for the first user is $50 and for the second $20, i.e., total revenue is $70. The total underlying cost is _$5 + $2 = $7_. Since your profit is 80% of the revenue minus the cost, it would be _0.8 * 70 - 7 = $49_. -
- -#### Best practices for PPR Actors - -To ensure profitable operation: - -- Set memory limits in your [`actor.json`](https://docs.apify.com/platform/actors/development/actor-definition/actor-json) file to control platform usage costs -- Implement the `ACTOR_MAX_PAID_DATASET_ITEMS` check to prevent excess result generation. You can copy [this simple solution](https://github.com/metalwarrior665/max-paid-items-example/blob/master/src/push-data.ts). -- Test your Actor with various result volumes to determine optimal pricing -- Push at least one "error item" to the dataset for invalid input or if search query didn't generate any result. This will prevent users running your Actor for free. - -### Pay-per-event (PPE) pricing model - -The pay-per-event pricing model offers a flexible monetization option for Actors on Apify Store. Unlike pay per result, PPE allows you to charge users based on specific events triggered programmatically by your Actor's code. - -#### PPE vs. PPR - -Unlike PPR, which charges based on the number of results produced, PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor by calling the PPE charging API. Common events include Actor start, dataset item creation, and external API calls. - -#### How is profit computed - -Your profit is calculated as follows: - -`profit = (0.8 * revenue) - platform costs` - -where: - -- _Revenue_: The amount charged for events via the PPE [API](/api/v2/post-charge-run) or through [JS](/sdk/js/reference/class/Actor#charge)/[Python](/sdk/python/reference/class/Actor#charge) SDK. You receive 80% of this revenue. -- _Platform costs_: The underlying platform usage costs for running the Actor, calculated in the same way as for PPR. For more details, visit the [Computing your costs for PPE and PPR Actors](#computing-your-costs-for-ppe-and-ppr-actors) section. - -Only paid user activity is included in profit calculations. - -:::note Negative profit isolation - -An Actor's negative net profit does not affect the positive profit of another Actor. For aggregation purposes, any Actor with a negative net profit is considered to have a profit of $0. - -- _Previously:_ `Total Profit = (-$90) + $100 = $10` -- _Now:_ `Total Profit = $0 + $100 = $100` - -::: - -#### How to set pricing for PPE - -1. _Understand your costs_: Analyze resource usage (e.g CPU, memory, proxies, external APIs) and identify cost drivers -1. _Define clear events_: break your Actor's functionality into measurable, chargeable events. -1. _Common use cases_: - 1. _For scraping_: combine Actor start and dataset items pricing to reflect setup and per-result cost. - 1. _Beyond scraping_: Account for integrations with external systems or external API calls. -1. _External API costs_: Account for additional processing costs. -1. _Test your pricing_: Run your Actor and analyze cost-effectiveness using a special dataset. -1. _Communicate value_: Ensure pricing reflects the value provided and is competitive. - -#### Best practices for PPE Actors - -- Set memory limits in your [`actor.json`](/platform/actors/development/actor-definition/actor-json) file to control platform usage costs -- Charge either for "Actor start" or for invalid input or empty search to prevent users from running your Actor for free. - - Don't charge the "Actor start" event again after Actor migration (check `ChargingManager` state). -- Finish the Actor run once charging reaches user-configured `Maximum cost per run`. Apify SDKs ([JS](/sdk/js/reference/class/Actor#charge) and [Python](/sdk/python/reference/class/Actor#charge)) return `ChargeResult` that helps determine when to finish. -- If you are not using the SDKs, use idempotency keys in API calls to prevent double charges. -- Try to limit the number of events. Fewer events make it easier for users to understand your pricing. -- Try to make your event have tangible artifacts that users can see and understand (this might not be possible when using external APIs) i.e: - - Get a record - - Save it to a dataset - - etc. - -:::note `ChargingManager` usage - -Use our SDKs ([JS](/sdk/js/reference/class/ChargingManager) and, [Python](/sdk/python/reference/class/ChargingManager) or use [`apify actor charge`](/cli/docs/next/reference#apify-actor-charge-eventname) when using our Apify CLI) to simplify PPE implementation into your Actor. This tool can handle pricing, usage tracking, idempotency keys, API errors, and, event charging via an API. - -You can also choose not to use it, but then you must handle API integration and possible edge cases manually. You can use `ChargingManager` code as a reference. - -::: - -#### PPE event names - -To implement pay-per-event pricing, you need to define specific events in your Actor code. You can retrieve the list of available pricing event names using the [Get Actor](https://apify.com/docs/api/v2/act-get) API endpoint. - -### How to attract larger customers of PPE and PPR Actors - -Each user running your PPE or PPR Actor belongs to a discount tier: - -- _FREE_ -- _BRONZE_ -- _SILVER_ -- _GOLD_ - - -You can define different prices for different tiers. -While optional, we recommend offering progressively lower prices for higher discount tiers. This approach can significantly improve attractiveness of your Actor to large enterprise customers who may spend thousands or tens of thousands of dollars on it. - -Your platform costs are also lower for these higher tier, which helps maintain healthy profit margins. This is further detailed in the [Computing your costs for PPE and PPR Actors](#computing-your-costs-for-ppe-and-ppr-actors) section. - -By default, we advise against setting excessively high prices for _FREE_ tier users, as this can limit the ability to evaluate your Actor thoroughly. However, in certain situations, such as protecting your Actor from fraudulent activity or excessive use of your internal APIs, a higher price for _FREE_ tier users might be justified. - -During an Actor run, you can identify the user's discount tier through Actor run environment variables or by querying user data via the Apify API. This capability allows you to offer premium features or differentiated service levels to users in higher discount tiers. - -In addition to the standard tiers, Apify provides further tiers specifically for enterprise customers, including _PLATINUM_ and _DIAMOND_ tiers. If you are interested in offering enterprise-level services and attracting major clients, please contact us. - -### Computing your costs for PPE and PPR Actors - -For both PPE and PPR Actors, profit is computed using the formula `(0.8 * revenue) - costs`. In this section, we'll explain how the `costs` component is calculated. - -When paying users run your Actor, it generates platform usage in the form of compute units, data traffic, API operations etc. This usage determines the `costs` in the profit formula above. - -:::note _FREE_ tier usage - -Platform usage by _FREE_ tier users is covered by Apify and does not contribute to your costs. - -::: - -To calculate your costs in dollars for a specific run by paying user, multiply the unit cost of each service by the quantity consumed. For example, if a _BRONZE_ tier user run uses 10 compute units (CUs) at $0.4/CU, your cost would be $4. - -As highlighted in the [How to attract larger customers of PPE and PPR Actors](#how-to-attract-larger-customers-of-ppe-and-ppr-actors) section, if your Actor uses tiered pricing, the user's discount tier determines the unit costs applied to their runs. Your costs are lower for higher tiers, enabling you to offer more competitive pricing to these customers, while sustaining healthy profit margins. - -The following table summarizes the platform unit costs used for your cost computation across different discount tiers. - -| Service | Price is per | _FREE_ | _BRONZE_ | _SILVER_ | _GOLD_ | -|:-------------------------------|:--------------|--------:|---------:|---------:|--------:| -| Compute unit | CU | $0.4 | $0.4 | $0.3 | $0.25 | -| Residential proxies | GB | $8 | $8 | $7.5 | $7 | -| SERPs proxy | 1,000 SERPs | $2.5 | $2.5 | $2 | $1.7 | -| Data transfer - external | GB | $0.2 | $0.2 | $0.19 | $0.18 | -| Data transfer - internal | GB | $0.05 | $0.05 | $0.045 | $0.04 | -| Dataset - reads | 1,000 reads | $0.0004 | $0.0004 | $0.00036 | $0.00032| -| Dataset - writes | 1,000 writes | $0.005 | $0.005 | $0.0045 | $0.004 | -| Key-value store - reads | 1,000 reads | $0.005 | $0.005 | $0.0045 | $0.004 | -| Key-value store - writes | 1,000 writes | $0.05 | $0.05 | $0.045 | $0.04 | -| Key-value store - lists | 1,000 lists | $0.05 | $0.05 | $0.045 | $0.04 | -| Request queue - reads | 1,000 reads | $0.004 | $0.004 | $0.0036 | $0.0032 | -| Request queue - writes | 1,000 writes | $0.02 | $0.02 | $0.018 | $0.016 | - -If you decide not to offer tiered discounts on your Actor, the unit prices for _FREE_ tier apply. To offer enterprise level services and unlock even cheaper unit prices for enterprise customers, please reach out to us. - -:::note Cost of PPE Actors in Standby mode - -When you monetize your Actor in Standby mode using pay per event mode only, you are not responsible for covering platform usage costs of your users' runs. - -::: - -## Setting up monetization - -Navigate to your [Actor page](https://console.apify.com/actors?tab=my) in Apify Console, choose the Actor that you want to monetize, and select the Publication tab. -![Monetization section](./images/monetization-section.png) -Open the Monetization section and complete your billing and payment details. -![Set up monetization](./images/monetize_actor_set_up_monetization.png) -Choose the pricing model for your Actor. -![Monetization wizard](./images/monetization_wizard.png) -Follow the monetization wizard to configure your pricing model. - - -![rental moentization wizard](./images/rental-wizard.png) - - -![ppr moentization wizard](./images/ppr-wizard.png) - - -![ppe moentization wizard](./images/ppe-wizard.png) - - - -## Changing monetization - -You can change the monetization setting of your Actor by using the same wizard as for the setup in the **Monetization** section of your Actor's **Publication** tab. Any changes made to an already published Actor will take _14 days_ to come into effect, so that the users of your Actor have time to prepare. - -:::important Frequency of monetization adjustments - -Be aware that you can change the monetization setting of each Actor only once per month. For further information and guidelines, please refer to our [Terms & Conditions](https://apify.com/store-terms-and-conditions) - -::: - -## Monthly payouts and analytics - -Payout invoices are automatically generated on the 11th of each month, summarizing the profits from all your Actors for the previous month. -In accordance with our [Terms & Conditions](https://apify.com/store-terms-and-conditions), only funds from legitimate users who have already paid are included in the payout invoice. - -:::note How negative profits are handled - -If your PPR or PPE Actor's price doesn't cover its monthly platform usage costs, it will have a negative profit. When this occurs, we automatically set that Actor's profit to $0 for the month. This ensures a single Actor's loss never reduces your total payout. - -::: - -You have 3 days to review your payout invoice in the **Development >Insights > Payout** section. During this period, you can either approve the invoice or request a revision, which we will process promptly. -If no action is taken, the payout will be automatically approved on the 14th, with funds disbursed shortly after. Payouts require meeting minimum thresholds of either: - -- $20 for PayPal -- $100 for other payout methods - -If the monthly profit does not meet these thresholds, as per our [Terms & Conditions](https://apify.com/store-terms-and-conditions), the funds will roll over to the next month until the threshold is reached. - -## Actor analytics - -Monitor your Actors' performance through the [Actor Analytics](https://console.apify.com/actors/insights/analytics) dashboard under **Development > Insights > Analytics**. - -The analytics dashboard allows you to select specific Actors and view key metrics aggregated across all user runs: - -- Revenue, costs and profit trends over time -- User growth metrics (both paid and free users) -- Cost per 1,000 results to optimize pricing -- Run success rate statistics -- User acquisition funnel analytics -- Shared debug runs from users - -All metrics can be exported as JSON for custom analysis and reporting. - -## Promoting your Actor - -Create serach-engine-optimized descriptions and README files to improve search engine visibility. Share your Actor on multiple channels: - -- Post on Reddit, Quora, and social media platforms -- Create tutorial videos demonstrating key features -- Publish articles about your Actor on relevant websites -- Consider creating a product showcase on platforms like Product Hunt - -Remember to tag Apify in your social media posts for additional exposure. Effective promotion can significantly impact your Actor's success, differentiating between those with many paid users and those with few to none. - -Learn more about promoting your Actor in the [Apify's marketing playbook](/academy/actor-marketing-playbook). - */} diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx index e4d6603434..73ddd33357 100644 --- a/sources/platform/actors/publishing/monetize/index.mdx +++ b/sources/platform/actors/publishing/monetize/index.mdx @@ -29,14 +29,17 @@ For a detailed comparison of pricing models from the perspective of your users, The following table compares the two main pricing models available for monetizing your Actors: -| Feature/Category | Rental pricing | Pay-per-event/result | -|------------------|----------------|---------------------| -| Revenue scalability | Capped at monthly fee | Unlimited, scales with usage | -| AI/MCP compatibility | ❌ Not compatible | ✅ Fully compatible | -| User cost predictability | Confusing (rental + usage) | Clear, transparent pricing | -| Tiered pricing support | ❌ Single price only | ✅ Store discounts available | -| Marketing boost* | Standard visibility | Priority store placement | -| Commission opportunities | Standard 20% | Promotional 0% periods | +| Feature/Category | Rental pricing | Pay-per-result (PPR) | Pay-per-event (PPE) | +|-------------------------|-------------------------------|------------------------------|-------------------------------| +| Revenue scalability | Capped at monthly fee | Unlimited, scales with usage | Unlimited, scales with usage | +| AI/MCP compatibility | ❌ Not compatible | ✅ Fully compatible | ✅ Fully compatible | +| User cost predictability| Confusing (rental + usage) | Clear, transparent pricing | Clear, transparent pricing | +| Tiered pricing support | ❌ Single price only | ✅ Store discounts available | ✅ Store discounts available | +| Marketing boost* | Standard visibility | Priority store placement | Priority store placement | +| Commission opportunities| Standard 20% | Promotional 0% periods | Promotional 0% periods | +| Custom event billing | Not available | Not available | ✅ Charge for any event | +| Per-result billing | Not available | ✅ Charge per dataset item | Optional (via event) | +| Flat monthly fee | ✅ Yes | Not available | Not available | ## Setting up monetization diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index 98d42deca2..a227656a9e 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -1,10 +1,14 @@ --- title: Pay per event (PPE) -description: TBD +description: Learn how to monetize your Actor with pay-per-event (PPE) pricing, charging users for specific actions like Actor starts, dataset items, or API calls, and understand how to set profitable, transparent event-based pricing. slug: /actors/publishing/monetize/pay-per-event sidebar_position: 3 --- +**Learn how to monetize your Actor with pay-per-event (PPE) pricing, charging users for specific actions like Actor starts, dataset items, or API calls, and understand how to set profitable, transparent event-based pricing.** + +--- + import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -12,6 +16,8 @@ The pay-per-event pricing model offers a flexible monetization option for Actors PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor by calling the [PPE charging API](/api/v2/post-charge-run), or through [JS](/sdk/js/reference/class/Actor#charge)/[Python](/sdk/python/reference/class/Actor#charge) SDK Common events include Actor start, dataset item creation, and external API calls. +The details on how your cost is computed can be found in [Example of a pay-per-event pricing model](#example-of-a-pay-per-event-pricing-model). + ## How is profit computed Your profit is calculated from the mentioned formula: @@ -69,7 +75,10 @@ Set memory limits using `minMemoryMbytes` and `maxMemoryMbytes` in your [`actor. Charge for "Actor start" to prevent users from running your Actor for free. -```typescript + + + +```js import { Actor } from 'apify'; const chargeForActorStart = async () => { @@ -88,7 +97,7 @@ await Actor.init(); const main = async () => { await chargeForActorStart(); - // Continue with the Actor's main logic + // Rest of the Actor logic }; await main(); @@ -96,6 +105,33 @@ await main(); await Actor.exit(); ``` + + + +```python +from apify import Actor + +async def charge_for_actor_start(): + charging_manager = Actor.get_charging_manager() + + # Don't charge the "Actor start" event again after Actor migration + # TODO: FIX + if charging_manager.get_charged_event_count("actor-start") == 0: + await Actor.charge(event_name="actor-start") + +async def main(): + await Actor.init() + + await charge_for_actor_start() + + # Rest of the Actor logic + + await Actor.exit() +``` + + + + :::note Actor migrations and charging Actors can migrate between servers during execution, which restarts the process and clears memory. When using PPE charging, avoid charging the start event multiple times after a migration by checking your charging state. @@ -105,17 +141,19 @@ Actors can migrate between servers during execution, which restarts the process Charge for invalid input or empty search to prevent users from running your Actor for free. -```typescript + + + +```js import { Actor } from 'apify'; -import { Input } from './types'; -const parseInput = async (input: Input) => { - if (!input.searchStringsArray && !input.startUrls && !input.allPlacesNoSearchAction) { +const parseInput = async (input) => { + if (!input.searchStringsArray && !input.startUrls) { await Actor.charge({ eventName: "invalid-input", }); - throw await Actor.fail('INVALID INPUT: You must provide either search terms, start URLs, or allPlacesNoSearchAction!'); + throw await Actor.fail('INVALID INPUT: You must provide either search terms, or start URLs!'); } return input; @@ -127,7 +165,7 @@ const main = async () => { const input = await Actor.getInput(); const parsedInput = await parseInput(input); - // Continue with the Actor's main logic + // Rest of the Actor logic }; await main(); @@ -135,14 +173,43 @@ await main(); await Actor.exit(); ``` + + + +```python +from apify import Actor + +async def parse_input(input_data): + if not input_data.get('searchStringsArray') and not input_data.get('startUrls'): + await Actor.charge(event_name='invalid-input') + + raise await Actor.fail('INVALID INPUT: You must provide either search terms, or start URLs!') + + return input_data + +async def main(): + await Actor.init() + + input_data = await Actor.get_input() + parsed_input = await parse_input(input_data) + + # Rest of the Actor logic + + await Actor.exit() +``` + + + + ### Respect user spending limits Finish the Actor run once charging reaches user-configured Maximum cost per run. Apify SDKs (JS and Python) return ChargeResult that helps determine when to finish. -```typescript -import { Actor } from 'apify'; + + -const MAX_COST = Number(process.env.ACTOR_MAX_TOTAL_CHARGE_USD); +```js +import { Actor } from 'apify'; const chargForApiCall = async () => { const chargeResult = await Actor.charge({ @@ -155,15 +222,15 @@ const chargForApiCall = async () => { await Actor.init(); const main = async () => { - // actual API call + // API call, or any other logic that you want to charge for const chargeResult = await chargForApiCall(); - if (chargeResult.totalCost >= MAX_COST) { + if (chargeResult.eventChargeLimitReached) { await Actor.exit(); } - // continue with the Actor's main logic + // Rest of the Actor logic }; await main(); @@ -171,172 +238,89 @@ await main(); await Actor.exit(); ``` -### Use idempotency keys to prevent double charges - -If you're not using the Apify SDKs (JS/Python), you need to handle idempotency (ensuring the same operation produces the same result when called multiple times) manually to prevent charging the same event multiple times. - -### Keep pricing simple with fewer events - -Try to limit the number of events. Fewer events make it easier for users to understand your pricing and predict their costs. - -### Make events produce tangible results - -Try to make your event have tangible artifacts that users can see and understand (this might not be possible when using external APIs). Each charged event should produce something concrete in the user's dataset. - -Good examples: - -- **"scraped-product"** event: Each charge adds one product record to the dataset -- **"processed-image"** event: Each charge adds one processed image to the dataset -- **"extracted-review"** event: Each charge adds one review to the dataset - -Avoid charging for: - -- Internal processing steps that don't produce visible results -- API calls that don't generate user-visible data -- Setup or configuration steps - -This helps users understand exactly what they're paying for and builds trust in your pricing model. - -## PPE event names - -To implement pay-per-event pricing, you need to define specific events in your Actor code. You can retrieve the list of available pricing event names using the [Get Actor](https://apify.com/docs/api/v2/act-get) API endpoint. - -## How to attract larger customers of PPE and PPR Actors - -Each user running your PPE or PPR Actor belongs to a discount tier: - -- _FREE_ -- _BRONZE_ -- _SILVER_ -- _GOLD_ - - -You can define different prices for different tiers. -While optional, we recommend offering progressively lower prices for higher discount tiers. This approach can significantly improve attractiveness of your Actor to large enterprise customers who may spend thousands or tens of thousands of dollars on it. - -Your platform costs are also lower for these higher tier, which helps maintain healthy profit margins. This is further detailed in the [Computing your costs for PPE and PPR Actors](#computing-your-costs-for-ppe-and-ppr-actors) section. - -By default, we advise against setting excessively high prices for _FREE_ tier users, as this can limit the ability to evaluate your Actor thoroughly. However, in certain situations, such as protecting your Actor from fraudulent activity or excessive use of your internal APIs, a higher price for _FREE_ tier users might be justified. - -During an Actor run, you can identify the user's discount tier through Actor run environment variables or by querying user data via the Apify API. This capability allows you to offer premium features or differentiated service levels to users in higher discount tiers. - -In addition to the standard tiers, Apify provides further tiers specifically for enterprise customers, including _PLATINUM_ and _DIAMOND_ tiers. If you are interested in offering enterprise-level services and attracting major clients, please contact us. - -## Computing your costs for PPE and PPR Actors - -For both PPE and PPR Actors, profit is computed using the formula `(0.8 * revenue) - costs`. In this section, we'll explain how the `costs` component is calculated. - -When paying users run your Actor, it generates platform usage in the form of compute units, data traffic, API operations etc. This usage determines the `costs` in the profit formula above. - -:::note _FREE_ tier usage - -Platform usage by _FREE_ tier users is covered by Apify and does not contribute to your costs. - -::: + + -To calculate your costs in dollars for a specific run by paying user, multiply the unit cost of each service by the quantity consumed. For example, if a _BRONZE_ tier user run uses 10 compute units (CUs) at $0.4/CU, your cost would be $4. +```python +from apify import Actor -As highlighted in the [How to attract larger customers of PPE and PPR Actors](#how-to-attract-larger-customers-of-ppe-and-ppr-actors) section, if your Actor uses tiered pricing, the user's discount tier determines the unit costs applied to their runs. Your costs are lower for higher tiers, enabling you to offer more competitive pricing to these customers, while sustaining healthy profit margins. +async def charge_for_api_call(): + charge_result = await Actor.charge(event_name='api-call') -The following table summarizes the platform unit costs used for your cost computation across different discount tiers. + return charge_result -| Service | Price is per | _FREE_ | _BRONZE_ | _SILVER_ | _GOLD_ | -|:-------------------------------|:--------------|--------:|---------:|---------:|--------:| -| Compute unit | CU | $0.4 | $0.4 | $0.3 | $0.25 | -| Residential proxies | GB | $8 | $8 | $7.5 | $7 | -| SERPs proxy | 1,000 SERPs | $2.5 | $2.5 | $2 | $1.7 | -| Data transfer - external | GB | $0.2 | $0.2 | $0.19 | $0.18 | -| Data transfer - internal | GB | $0.05 | $0.05 | $0.045 | $0.04 | -| Dataset - reads | 1,000 reads | $0.0004 | $0.0004 | $0.00036 | $0.00032| -| Dataset - writes | 1,000 writes | $0.005 | $0.005 | $0.0045 | $0.004 | -| Key-value store - reads | 1,000 reads | $0.005 | $0.005 | $0.0045 | $0.004 | -| Key-value store - writes | 1,000 writes | $0.05 | $0.05 | $0.045 | $0.04 | -| Key-value store - lists | 1,000 lists | $0.05 | $0.05 | $0.045 | $0.04 | -| Request queue - reads | 1,000 reads | $0.004 | $0.004 | $0.0036 | $0.0032 | -| Request queue - writes | 1,000 writes | $0.02 | $0.02 | $0.018 | $0.016 | +async def main(): + await Actor.init() + + # API call, or any other logic that you want to charge for -If you decide not to offer tiered discounts on your Actor, the unit prices for _FREE_ tier apply. To offer enterprise level services and unlock even cheaper unit prices for enterprise customers, please reach out to us. + charge_result = await charge_for_api_call() -:::note Cost of PPE Actors in Standby mode + if charge_result.event_charge_limit_reached: + await Actor.exit() -When you monetize your Actor in Standby mode using pay per event mode only, you are not responsible for covering platform usage costs of your users' runs. + # Rest of the Actor logic -::: + await Actor.exit() +``` -## Setting up monetization - -Navigate to your [Actor page](https://console.apify.com/actors?tab=my) in Apify Console, choose the Actor that you want to monetize, and select the Publication tab. -![Monetization section](../images/monetization-section.png) -Open the Monetization section and complete your billing and payment details. -![Set up monetization](../images/monetize_actor_set_up_monetization.png) -Choose the pricing model for your Actor. -![Monetization wizard](../images/monetization_wizard.png) -Follow the monetization wizard to configure your pricing model. - - -![rental moentization wizard](../images/rental-wizard.png) - - -![ppr moentization wizard](../images/ppr-wizard.png) - - -![ppe moentization wizard](../images/ppe-wizard.png) -## Changing monetization - -You can change the monetization setting of your Actor by using the same wizard as for the setup in the **Monetization** section of your Actor's **Publication** tab. Any changes made to an already published Actor will take _14 days_ to come into effect, so that the users of your Actor have time to prepare. +### Use idempotency keys to prevent double charges -:::important Frequency of monetization adjustments +If you're not using the Apify SDKs (JS/Python), you need to handle idempotency (ensuring the same operation produces the same result when called multiple times) manually to prevent charging the same event multiple times. -Be aware that you can change the monetization setting of each Actor only once per month. For further information and guidelines, please refer to our [Terms & Conditions](https://apify.com/store-terms-and-conditions) +### Keep pricing simple with fewer events -::: +Try to limit the number of events. Fewer events make it easier for users to understand your pricing and predict their costs. -## Monthly payouts and analytics +### Make events produce visible results -Payout invoices are automatically generated on the 11th of each month, summarizing the profits from all your Actors for the previous month. -In accordance with our [Terms & Conditions](https://apify.com/store-terms-and-conditions), only funds from legitimate users who have already paid are included in the payout invoice. +Try to make your event have tangible artifacts that users can see and understand (this might not be possible when using external APIs). Each charged event should produce something concrete in the user's dataset. -:::note How negative profits are handled +Good examples: -If your PPR or PPE Actor's price doesn't cover its monthly platform usage costs, it will have a negative profit. When this occurs, we automatically set that Actor's profit to $0 for the month. This ensures a single Actor's loss never reduces your total payout. +- _"scraped-product" event_: Each charge adds one product record to the dataset +- _"processed-image" event_: Each charge adds one processed image to the dataset +- _"extracted-review" event_: Each charge adds one review to the dataset -::: +Avoid charging for: -You have 3 days to review your payout invoice in the **Development >Insights > Payout** section. During this period, you can either approve the invoice or request a revision, which we will process promptly. -If no action is taken, the payout will be automatically approved on the 14th, with funds disbursed shortly after. Payouts require meeting minimum thresholds of either: +- Internal processing steps that don't produce visible results +- API calls that don't generate user-visible data +- Setup or configuration steps -- $20 for PayPal -- $100 for other payout methods +This helps users understand exactly what they're paying for and builds trust in your pricing model. -If the monthly profit does not meet these thresholds, as per our [Terms & Conditions](https://apify.com/store-terms-and-conditions), the funds will roll over to the next month until the threshold is reached. +## Example of a pay-per-event pricing model -## Actor analytics +You make your Actor pay-per-event and set the following pricing: +- _"actor-start" event_: $0.10 per start +- _"scraped-product" event_: $0.01 per product +- _"api-call" event_: $0.05 per API call -Monitor your Actors' performance through the [Actor Analytics](https://console.apify.com/actors/insights/analytics) dashboard under **Development > Insights > Analytics**. +During the first month, three users use your Actor: -The analytics dashboard allows you to select specific Actors and view key metrics aggregated across all user runs: +- _User 1 (paid plan)_: Starts Actor 5 times, scrapes 1,000 products, makes 50 API calls + - Charges: 5 × $0.10 + 1,000 × $0.01 + 50 × $0.05 = $0.50 + $10.00 + $2.50 = $13.00 +- _User 2 (paid plan)_: Starts Actor 2 times, scrapes 500 products, makes 20 API calls + - Charges: 2 × $0.10 + 500 × $0.01 + 20 × $0.05 = $0.20 + $5.00 + $1.00 = $6.20 +- _User 3 (free plan)_: Starts Actor 1 time, scrapes 100 products, makes 5 API calls + - Charges: 1 × $0.10 + 100 × $0.01 + 5 × $0.05 = $0.10 + $1.00 + $0.25 = $1.35 -- Revenue, costs and profit trends over time -- User growth metrics (both paid and free users) -- Cost per 1,000 results to optimize pricing -- Run success rate statistics -- User acquisition funnel analytics -- Shared debug runs from users +Let's say the underlying platform usage for the first user is $2.50, for the second $1.20, and for the third $0.30. -All metrics can be exported as JSON for custom analysis and reporting. +Your profit is computed only from the first two users, since they are on Apify paid plans. The revenue breakdown is: -## Promoting your Actor +- _Total revenue_: $13.00 + $6.20 = $19.20 +- _Total underlying cost_: $2.50 + $1.20 = $3.70 +- _Your profit_: 80% of revenue minus costs = 0.8 × $19.20 - $3.70 = $11.66 -Create serach-engine-optimized descriptions and README files to improve search engine visibility. Share your Actor on multiple channels: +## PPE event names -- Post on Reddit, Quora, and social media platforms -- Create tutorial videos demonstrating key features -- Publish articles about your Actor on relevant websites -- Consider creating a product showcase on platforms like Product Hunt +To implement pay-per-event pricing, you need to define specific events in your Actor code. You can retrieve the list of available pricing event names using the [Get Actor](https://apify.com/docs/api/v2/act-get) API endpoint. -Remember to tag Apify in your social media posts for additional exposure. Effective promotion can significantly impact your Actor's success, differentiating between those with many paid users and those with few to none. +## Next steps -Learn more about promoting your Actor in the [Apify's marketing playbook](/academy/actor-marketing-playbook). \ No newline at end of file +- Check out the [Pricing and costs](/actors/publishing/monetize/pricing-and-costs) section to learn how to compute your costs. diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index 96bafe004c..6e05fc6b7d 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -1,14 +1,27 @@ --- title: Pay per result (PPR) -description: TBD +description: Learn how to monetize your Actor with pay-per-result (PPR) pricing, charging users based on the number of results produced and stored in the dataset, and understand how to set profitable, transparent result-based pricing. slug: /actors/publishing/monetize/pay-per-result sidebar_position: 2 --- +**Learn how to monetize your Actor with pay-per-result (PPR) pricing, charging users based on the number of results produced and stored in the dataset, and understand how to set profitable, transparent result-based pricing.** + +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + In this model, you set a price per 1,000 results. Users are charged based on the number of results your Actor produces and stores in the run's default dataset. Your profit is calculated as 80% of the revenue minus platform usage costs. The details on how your cost is computed can be found in [Example of a pay-per-result pricing model](#example-of-a-pay-per-result-pricing-model). +## Pay-per-result (PPR) vs. pay-per-event (PPE) + +Unlike PPR, which charges based on the number of results produced, PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor by calling the PPE charging API. Common events include Actor start, dataset item creation, and external API calls. + +If you're interested in learning more about PPE, check out the [Pay per event (PPE)](/platform/actors/publishing/monetize/pay-per-event) section. + ## How is profit computed Your profit is calculated from the mentioned formula: @@ -46,26 +59,56 @@ This check prevents your Actor from generating more results than the user has pa The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for paid-per-result Actors. Do not exceed this limit. -```typescript + + + +```js const MAX_ITEMS = Number(process.env.ACTOR_MAX_PAID_DATASET_ITEMS); let pushedItemCount = 0; -export const pushDataMaxAware = async (data: Parameters[0]) => { - // rest of the code... +export const pushDataMaxAware = async (data) => { + // rest of the Actor logic const dataAsArray = Array.isArray(data) ? data : [data]; const dataToPush = dataAsArray.slice(0, MAX_ITEMS - pushedItemCount); if (dataToPush.length) { - // We have to update the state before 'await' to avoid race conditions pushedItemCount += dataToPush.length; await Actor.pushData(dataToPush); } - // rest of the code... + // rest of the Actor logic } ``` + + + +```python +import os +from apify import Actor + +MAX_ITEMS = int(os.getenv('ACTOR_MAX_PAID_DATASET_ITEMS', 0)) + +# rest of the Actor logic + +async def push_data_max_aware(data, pushed_item_count=0): + data_as_array = data if isinstance(data, list) else [data] + data_to_push = data_as_array[:MAX_ITEMS - pushed_item_count] + + if data_to_push: + new_count = pushed_item_count + len(data_to_push) + await Actor.push_data(data_to_push) + return new_count + + return pushed_item_count + +# rest of the Actor logic +``` + + + + You can find the whole code of implementing this check in this [example](https://github.com/metalwarrior665/max-paid-items-example/blob/master/src/push-data.ts). ### Test your Actor @@ -80,15 +123,15 @@ In PPR Actors, users are only charged when your Actor produces results in the da Why this matters: -- **Prevents free usage**: Without pushing any items, users could run your Actor repeatedly with invalid inputs without being charged -- **Ensures fair billing**: Users should pay for the processing attempt, even if no valid results are found -- **Maintains profitability**: Every run should generate some revenue to cover your platform costs +- _Prevents free usage_: Without pushing any items, users could run your Actor repeatedly with invalid inputs without being charged +- _Ensures fair billing_: Users should pay for the processing attempt, even if no valid results are found +- _Maintains profitability_: Every run should generate some revenue to cover your platform costs Example scenarios: -- **User provides invalid search terms**: Push an error item explaining the issue -- **Target website returns no results**: Push an item indicating "No results found" -- **Input validation fails**: Push an item with validation error details +- _User provides invalid search terms_: Push an error item explaining the issue +- _Target website returns no results_: Push an item indicating "No results found" +- _Input validation fails_: Push an item with validation error details This ensures that every run generates at least one result, guaranteeing that users are charged appropriately for using your Actor. @@ -96,14 +139,18 @@ This ensures that every run generates at least one result, guaranteeing that use You make your Actor pay-per-result and set the price to be **$1/1,000 results**. During the first month, three users use your Actor: -- **User 1** (paid plan): Gets 50,000 results, costing them $50 -- **User 2** (paid plan): Gets 20,000 results, costing them $20 -- **User 3** (free plan): Gets 5,000 results, costing them $0 +- _User 1 (paid plan)_: Gets 50,000 results, costing them $50 +- _User 2 (paid plan)_: Gets 20,000 results, costing them $20 +- _User 3 (free plan)_: Gets 5,000 results, costing them $0 Let's say the underlying platform usage for the first user is $5, for the second $2, and for the third $0.5. Your profit is computed only from the first two users, since they are on Apify paid plans. The revenue breakdown is: -- **Total revenue**: $50 + $20 = $70 -- **Total underlying cost**: $5 + $2 = $7 -- **Your profit**: 80% of revenue minus costs = 0.8 × $70 - $7 = **$49** +- _Total revenue_: $50 + $20 = $70 +- _Total underlying cost_: $5 + $2 = $7 +- _Your profit_: 80% of revenue minus costs = 0.8 × $70 - $7 = $49 + +## Next steps + +- Check out the [Pricing and costs](/actors/publishing/monetize/pricing-and-costs) section to learn how to compute your costs. diff --git a/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx b/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx new file mode 100644 index 0000000000..67bdc4d0bd --- /dev/null +++ b/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx @@ -0,0 +1,72 @@ +--- +title: Pricing and costs +description: Learn how to set Actor pricing and calculate your costs, including platform usage rates, discount tiers, and profit formulas for PPE and PPR monetization models. +slug: /actors/publishing/monetize/pricing-and-costs +sidebar_position: 3 +--- + +**Learn how to set Actor pricing and calculate your costs, including platform usage rates, discount tiers, and profit formulas for PPE and PPR monetization models.** + +--- + +## Computing your costs for PPE and PPR Actors + +For both PPE and PPR Actors, profit is computed using the formula `(0.8 * revenue) - costs`. In this section, we'll explain how the `costs` component is calculated. + +When paying users run your Actor, it generates platform usage in the form of compute units, data traffic, API operations etc. This usage determines the `costs` in the profit formula above. + +:::note _FREE_ tier usage + +Platform usage by _FREE_ tier users is covered by Apify and does not contribute to your costs. + +::: + +To calculate your costs in dollars for a specific run by paying user, multiply the unit cost of each service by the quantity consumed. For example, if a _BRONZE_ tier user run uses 10 compute units (CUs) at $0.4/CU, your cost would be $4. + +As highlighted in the [How to attract larger customers of PPE and PPR Actors](#how-to-attract-larger-customers-of-ppe-and-ppr-actors) section, if your Actor uses tiered pricing, the user's discount tier determines the unit costs applied to their runs. Your costs are lower for higher tiers, enabling you to offer more competitive pricing to these customers, while sustaining healthy profit margins. + +The following table summarizes the platform unit costs used for your cost computation across different discount tiers. + +| Service | Price is per | _FREE_ | _BRONZE_ | _SILVER_ | _GOLD_ | +|:-------------------------------|:--------------|--------:|---------:|---------:|--------:| +| Compute unit | CU | $0.4 | $0.4 | $0.3 | $0.25 | +| Residential proxies | GB | $8 | $8 | $7.5 | $7 | +| SERPs proxy | 1,000 SERPs | $2.5 | $2.5 | $2 | $1.7 | +| Data transfer - external | GB | $0.2 | $0.2 | $0.19 | $0.18 | +| Data transfer - internal | GB | $0.05 | $0.05 | $0.045 | $0.04 | +| Dataset - reads | 1,000 reads | $0.0004 | $0.0004 | $0.00036 | $0.00032| +| Dataset - writes | 1,000 writes | $0.005 | $0.005 | $0.0045 | $0.004 | +| Key-value store - reads | 1,000 reads | $0.005 | $0.005 | $0.0045 | $0.004 | +| Key-value store - writes | 1,000 writes | $0.05 | $0.05 | $0.045 | $0.04 | +| Key-value store - lists | 1,000 lists | $0.05 | $0.05 | $0.045 | $0.04 | +| Request queue - reads | 1,000 reads | $0.004 | $0.004 | $0.0036 | $0.0032 | +| Request queue - writes | 1,000 writes | $0.02 | $0.02 | $0.018 | $0.016 | + +If you decide not to offer tiered discounts on your Actor, the unit prices for _FREE_ tier apply. To offer enterprise level services and unlock even cheaper unit prices for enterprise customers, please reach out to us. + +:::note Cost of PPE Actors in Standby mode + +When you monetize your Actor in Standby mode using pay per event mode only, you are not responsible for covering platform usage costs of your users' runs. + +::: + + +## How to attract larger customers of PPE and PPR Actors + +Each user running your PPE or PPR Actor belongs to a discount tier: + +- _FREE_ +- _BRONZE_ +- _SILVER_ +- _GOLD_ + +You can define different prices for different tiers. +While optional, we recommend offering progressively lower prices for higher discount tiers. This approach can significantly improve attractiveness of your Actor to large enterprise customers who may spend thousands or tens of thousands of dollars on it. + +Your platform costs are also lower for these higher tier, which helps maintain healthy profit margins. This is further detailed in the [Computing your costs for PPE and PPR Actors](#computing-your-costs-for-ppe-and-ppr-actors) section. + +By default, we advise against setting excessively high prices for _FREE_ tier users, as this can limit the ability to evaluate your Actor thoroughly. However, in certain situations, such as protecting your Actor from fraudulent activity or excessive use of your internal APIs, a higher price for _FREE_ tier users might be justified. + +During an Actor run, you can identify the user's discount tier through Actor run environment variables or by querying user data via the Apify API. This capability allows you to offer premium features or differentiated service levels to users in higher discount tiers. + +In addition to the standard tiers, Apify provides further tiers specifically for enterprise customers, including _PLATINUM_ and _DIAMOND_ tiers. If you are interested in offering enterprise-level services and attracting major clients, please contact us. diff --git a/sources/platform/actors/publishing/monetize/rental.mdx b/sources/platform/actors/publishing/monetize/rental.mdx index d174284df2..8e154adecb 100644 --- a/sources/platform/actors/publishing/monetize/rental.mdx +++ b/sources/platform/actors/publishing/monetize/rental.mdx @@ -1,10 +1,14 @@ --- title: Rental pricing model -description: TBD +description: Learn how to monetize your Actor with the rental pricing model, offering users a free trial and a flat monthly fee, and understand how profit is calculated and the limitations of this approach. slug: /actors/publishing/monetize/rental sidebar_position: 1 --- +**Learn how to monetize your Actor with the rental pricing model, offering users a free trial and a flat monthly fee, and understand how profit is calculated and the limitations of this approach.** + +--- + With the rental model, you can specify a free trial period and a monthly rental price. After the trial, users with an [Apify paid plan](https://apify.com/pricing) can continue using your Actor by paying the monthly fee. You can receive 80% of the total rental fees collected each month. ## How is profit computed From 7145a174e3b62b6e202fe9bd4a11f288fdfdf70a Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Thu, 4 Sep 2025 09:13:16 +0200 Subject: [PATCH 03/21] Fix lint errors --- sources/platform/actors/publishing/monetize/pay_per_event.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index a227656a9e..ce6c95eb6a 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -296,6 +296,7 @@ This helps users understand exactly what they're paying for and builds trust in ## Example of a pay-per-event pricing model You make your Actor pay-per-event and set the following pricing: + - _"actor-start" event_: $0.10 per start - _"scraped-product" event_: $0.01 per product - _"api-call" event_: $0.05 per API call From 4500938785fdc486a2506d5e54b7044e65a12283 Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Thu, 4 Sep 2025 09:15:25 +0200 Subject: [PATCH 04/21] Fix lint errors --- .../platform/actors/publishing/monetize/pay_per_result.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index 6e05fc6b7d..e5fe6166b8 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -12,7 +12,7 @@ sidebar_position: 2 import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -In this model, you set a price per 1,000 results. Users are charged based on the number of results your Actor produces and stores in the run's default dataset. Your profit is calculated as 80% of the revenue minus platform usage costs. +In this model, you set a price per 1,000 results. Users are charged based on the number of results your Actor produces and stores in the run's default dataset. Your profit is calculated as 80% of the revenue minus platform usage costs. The details on how your cost is computed can be found in [Example of a pay-per-result pricing model](#example-of-a-pay-per-result-pricing-model). @@ -55,7 +55,7 @@ Set memory limits using `minMemoryMbytes` and `maxMemoryMbytes` in your [`actor. ### Implement the `ACTOR_MAX_PAID_DATASET_ITEMS` check -This check prevents your Actor from generating more results than the user has paid for, protecting both you and your users from unexpected costs. +This check prevents your Actor from generating more results than the user has paid for, protecting both you and your users from unexpected costs. The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for paid-per-result Actors. Do not exceed this limit. From 196e832766ecbcdd92a11e394ca5b4c670106f3a Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Thu, 4 Sep 2025 09:24:54 +0200 Subject: [PATCH 05/21] Fix build errors --- sources/platform/actors/index.mdx | 2 +- sources/platform/actors/publishing/monetize/pay_per_event.mdx | 2 +- sources/platform/actors/publishing/monetize/pay_per_result.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sources/platform/actors/index.mdx b/sources/platform/actors/index.mdx index a349494bcd..6586f43d3a 100644 --- a/sources/platform/actors/index.mdx +++ b/sources/platform/actors/index.mdx @@ -65,7 +65,7 @@ Ready to start? Check out the [Actor development documentation](/platform/actors ## Running Actors -You can run Actors manually in [Apify Console](https://console.apify.com/actors), using the [API](/api), [CLI](/cli), or [scheduler](../schedules.md). You can easily [integrate Actors](../integrations/index.mdx) with other apps, [share](../collaboration/access_rights.md) them with other people, [publish](./publishing/index.mdx) them in [Apify Store](https://apify.com/store), and even [monetize](./publishing/monetize.mdx). +You can run Actors manually in [Apify Console](https://console.apify.com/actors), using the [API](/api), [CLI](/cli), or [scheduler](../schedules.md). You can easily [integrate Actors](../integrations/index.mdx) with other apps, [share](../collaboration/access_rights.md) them with other people, [publish](./publishing/index.mdx) them in [Apify Store](https://apify.com/store), and even [monetize](./publishing/monetize/index.mdx). :::tip Try Actors diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index ce6c95eb6a..3d1e9f742e 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -324,4 +324,4 @@ To implement pay-per-event pricing, you need to define specific events in your A ## Next steps -- Check out the [Pricing and costs](/actors/publishing/monetize/pricing-and-costs) section to learn how to compute your costs. +- Check out the [Pricing and costs](./pricing_and_costs.mdx) section to learn how to compute your costs. diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index e5fe6166b8..d0180dd624 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -153,4 +153,4 @@ Your profit is computed only from the first two users, since they are on Apify p ## Next steps -- Check out the [Pricing and costs](/actors/publishing/monetize/pricing-and-costs) section to learn how to compute your costs. +- Check out the [Pricing and costs](./pricing_and_costs.mdx) section to learn how to compute your costs. From 7fd6f7777cf0be27534ada1421cfe4c45de6437b Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Thu, 4 Sep 2025 09:47:24 +0200 Subject: [PATCH 06/21] Add correct python method --- sources/platform/actors/publishing/monetize/pay_per_event.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index 3d1e9f742e..da24966571 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -115,7 +115,6 @@ async def charge_for_actor_start(): charging_manager = Actor.get_charging_manager() # Don't charge the "Actor start" event again after Actor migration - # TODO: FIX if charging_manager.get_charged_event_count("actor-start") == 0: await Actor.charge(event_name="actor-start") From 5280723df9969e5e58f2b2b29df9ebbd26b5f9fb Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Thu, 4 Sep 2025 10:08:54 +0200 Subject: [PATCH 07/21] Fix stylistic issue --- sources/platform/actors/publishing/monetize/rental.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/rental.mdx b/sources/platform/actors/publishing/monetize/rental.mdx index 8e154adecb..bba8f36255 100644 --- a/sources/platform/actors/publishing/monetize/rental.mdx +++ b/sources/platform/actors/publishing/monetize/rental.mdx @@ -45,13 +45,13 @@ Based on the reasons mentioned in [Disadvantages of the rental pricing model](#d You make your Actor rental with **7-day free trial** and then **$30/month**. During the first calendar month, three users start to use your Actor: -- **User 1** (paid plan): Starts free trial on the 15th -- **User 2** (paid plan): Starts free trial on the 25th -- **User 3** (free plan): Starts free trial on the 20th +- _User 1 (paid plan)_: Starts free trial on the 15th +- _User 2 (paid plan)_: Starts free trial on the 25th +- _User 3 (free plan)_: Starts free trial on the 20th The first user pays their first rent 7 days after the free trial, i.e., on the 22nd of the month. The second user only starts paying the rent next month. The third user is on the Apify free plan, so after the free trial ends on the 27th of the month, they are not charged and cannot use the Actor further until they get a paid plan. Your profit is computed only from the first user, since they are the only one who paid during this month. The revenue breakdown is: -- **Total revenue**: $30 (from User 1 only) -- **Your profit**: 80% of revenue = 0.8 × $30 = **$24** +- _Total revenue_: $30 (from User 1 only) +- _Your profit_: 80% of revenue = 0.8 × $30 = $24 From 3508d8bcb2f4071c162e2af9e3f7e9bfbb678cb0 Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Fri, 5 Sep 2025 15:17:10 +0200 Subject: [PATCH 08/21] docs: Pay per result PR comments fixes --- .../publishing/monetize/pay_per_event.mdx | 87 ++++++++++++++----- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index da24966571..96937451ec 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -66,11 +66,17 @@ Set memory limits using `minMemoryMbytes` and `maxMemoryMbytes` in your [`actor. "actorSpecification": 1, "name": "name-of-my-scraper", "version": "0.0", - "minMemoryMbytes": 256, - "maxMemoryMbytes": 4096, + "minMemoryMbytes": 512, + "maxMemoryMbytes": 1024, } ``` +:::note Memory requirements for browser-based scraping + +When using browser automation tools like Puppeteer or Playwright for web scraping, increase the memory limits to accommodate the browser's memory usage. + +::: + ### Charge for "Actor start" Charge for "Actor start" to prevent users from running your Actor for free. @@ -134,11 +140,12 @@ async def main(): :::note Actor migrations and charging Actors can migrate between servers during execution, which restarts the process and clears memory. When using PPE charging, avoid charging the start event multiple times after a migration by checking your charging state. + ::: ### Charge for invalid input -Charge for invalid input or empty search to prevent users from running your Actor for free. +Charge for things like URLs that appear valid but lead to errors (like 404s) since you actually had to open the page to discover the error. Return error items with proper error codes and messages instead of failing the entire Actor run. @@ -146,24 +153,38 @@ Charge for invalid input or empty search to prevent users from running your Acto ```js import { Actor } from 'apify'; -const parseInput = async (input) => { - if (!input.searchStringsArray && !input.startUrls) { +const processUrl = async (url) => { + const response = await fetch(url); + + if (response.status === 404) { + // Charge for the work done (opening the page) await Actor.charge({ - eventName: "invalid-input", + eventName: "scraped-result", + }); + + // Return error item instead of failing + await Actor.pushData({ + url: url, + error: "404", + errorMessage: "Page not found" }); - throw await Actor.fail('INVALID INPUT: You must provide either search terms, or start URLs!'); + return; } - return input; + // Rest of the Actor logic }; await Actor.init(); const main = async () => { const input = await Actor.getInput(); - const parsedInput = await parseInput(input); + const { urls } = input; + for (const url of urls) { + await processUrl(url); + } + // Rest of the Actor logic }; @@ -177,23 +198,37 @@ await Actor.exit(); ```python from apify import Actor +import requests -async def parse_input(input_data): - if not input_data.get('searchStringsArray') and not input_data.get('startUrls'): - await Actor.charge(event_name='invalid-input') +async def process_url(url): + response = requests.get(url) + + if response.status_code == 404: + # Charge for the work done (opening the page) + await Actor.charge(event_name='scraped-result') + + # Return error item instead of failing + await Actor.push_data({ + 'url': url, + 'error': '404', + 'errorMessage': 'Page not found' + }) - raise await Actor.fail('INVALID INPUT: You must provide either search terms, or start URLs!') + return - return input_data + # Rest of the Actor logic async def main(): await Actor.init() input_data = await Actor.get_input() - parsed_input = await parse_input(input_data) + urls = input_data.get('urls', []) + + for url in urls: + await process_url(url) # Rest of the Actor logic - + await Actor.exit() ``` @@ -204,6 +239,8 @@ async def main(): Finish the Actor run once charging reaches user-configured Maximum cost per run. Apify SDKs (JS and Python) return ChargeResult that helps determine when to finish. +The `eventChargeLimitReached` property checks if the current event type can be charged more. If you have multiple event types, analyze the `chargeableWithinLimit` property to see if other events can still be charged before stopping the Actor. + @@ -266,9 +303,11 @@ async def main(): -### Use idempotency keys to prevent double charges +:::note Crawlee integration and spending limits -If you're not using the Apify SDKs (JS/Python), you need to handle idempotency (ensuring the same operation produces the same result when called multiple times) manually to prevent charging the same event multiple times. +When using [Crawlee](https://crawlee.dev/), use `crawler.autoscaledPool.abort()` instead of `Actor.exit()` to gracefully finish the crawler and allow the rest of your code to process normally. + +::: ### Keep pricing simple with fewer events @@ -292,21 +331,25 @@ Avoid charging for: This helps users understand exactly what they're paying for and builds trust in your pricing model. +### Use idempotency keys to prevent double charges + +If you're not using the Apify SDKs (JS/Python), you need to handle idempotency (ensuring the same operation produces the same result when called multiple times) manually to prevent charging the same event multiple times. + ## Example of a pay-per-event pricing model You make your Actor pay-per-event and set the following pricing: - _"actor-start" event_: $0.10 per start - _"scraped-product" event_: $0.01 per product -- _"api-call" event_: $0.05 per API call +- _"scraped-product-detail" event_: $0.05 per detail During the first month, three users use your Actor: -- _User 1 (paid plan)_: Starts Actor 5 times, scrapes 1,000 products, makes 50 API calls +- _User 1 (paid plan)_: Starts Actor 5 times, scrapes 1,000 products, makes 50 product details - Charges: 5 × $0.10 + 1,000 × $0.01 + 50 × $0.05 = $0.50 + $10.00 + $2.50 = $13.00 -- _User 2 (paid plan)_: Starts Actor 2 times, scrapes 500 products, makes 20 API calls +- _User 2 (paid plan)_: Starts Actor 2 times, scrapes 500 products, makes 20 product details - Charges: 2 × $0.10 + 500 × $0.01 + 20 × $0.05 = $0.20 + $5.00 + $1.00 = $6.20 -- _User 3 (free plan)_: Starts Actor 1 time, scrapes 100 products, makes 5 API calls +- _User 3 (free plan)_: Starts Actor 1 time, scrapes 100 products, makes 5 product details - Charges: 1 × $0.10 + 100 × $0.01 + 5 × $0.05 = $0.10 + $1.00 + $0.25 = $1.35 Let's say the underlying platform usage for the first user is $2.50, for the second $1.20, and for the third $0.30. From 951b4442adad372aeb6242ee85cbf8d9296381da Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Fri, 5 Sep 2025 15:30:39 +0200 Subject: [PATCH 09/21] docs: Fix PR comments in PPR --- .../publishing/monetize/pay_per_result.mdx | 111 +++++++++++++----- 1 file changed, 84 insertions(+), 27 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index d0180dd624..9d7b324039 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -48,37 +48,69 @@ Set memory limits using `minMemoryMbytes` and `maxMemoryMbytes` in your [`actor. "actorSpecification": 1, "name": "name-of-my-scraper", "version": "0.0", - "minMemoryMbytes": 256, - "maxMemoryMbytes": 4096, + "minMemoryMbytes": 512, + "maxMemoryMbytes": 1024, } ``` +:::note Memory requirements for browser-based scraping + +When using browser automation tools like Puppeteer or Playwright for web scraping, increase the memory limits to accommodate the browser's memory usage. + +::: + ### Implement the `ACTOR_MAX_PAID_DATASET_ITEMS` check This check prevents your Actor from generating more results than the user has paid for, protecting both you and your users from unexpected costs. -The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for paid-per-result Actors. Do not exceed this limit. +The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for paid-per-result Actors. Do not exceed this limit. You can see the example implementation in the following code snippets. ```js -const MAX_ITEMS = Number(process.env.ACTOR_MAX_PAID_DATASET_ITEMS); +import { Actor } from 'apify'; + +// Use top-level variables with a closure so you don't have to initialize anything +const MAX_ITEMS: number | undefined = Number(process.env.ACTOR_MAX_PAID_DATASET_ITEMS) || undefined; + +let isInitialized = false; +let isGettingItemCount = false; let pushedItemCount = 0; -export const pushDataMaxAware = async (data) => { - // rest of the Actor logic +export const pushDataMaxAware = async (data: Parameters[0]): Promise<{ shouldStop: boolean }> => { + // If this isn't pay-per-result, just push like normallyå + if (!MAX_ITEMS) { + await Actor.pushData(data); + return { shouldStop: false }; + } + + // Initialize on the first call so it as standalone function + if (!isInitialized && !isGettingItemCount) { + isGettingItemCount = true; + const dataset = await Actor.openDataset(); + const { itemCount } = (await dataset.getInfo())!; + pushedItemCount = itemCount; + isGettingItemCount = false; + isInitialized = true; + } + + // Others handlers will wait until initialized which should be few milliseconds + while (!isInitialized) { + await new Promise((resolve) => setTimeout(resolve, 50)); + } const dataAsArray = Array.isArray(data) ? data : [data]; const dataToPush = dataAsArray.slice(0, MAX_ITEMS - pushedItemCount); if (dataToPush.length) { + // Update the state before 'await' to avoid race conditions pushedItemCount += dataToPush.length; await Actor.pushData(dataToPush); } - // rest of the Actor logic -} + return { shouldStop: pushedItemCount >= MAX_ITEMS }; +}; ``` @@ -87,30 +119,55 @@ export const pushDataMaxAware = async (data) => { ```python import os from apify import Actor - -MAX_ITEMS = int(os.getenv('ACTOR_MAX_PAID_DATASET_ITEMS', 0)) - -# rest of the Actor logic - -async def push_data_max_aware(data, pushed_item_count=0): - data_as_array = data if isinstance(data, list) else [data] - data_to_push = data_as_array[:MAX_ITEMS - pushed_item_count] - - if data_to_push: - new_count = pushed_item_count + len(data_to_push) - await Actor.push_data(data_to_push) - return new_count - - return pushed_item_count - -# rest of the Actor logic +from typing import Union, List, Dict, Any + +class PayPerResultManager: + def __init__(self): + self.max_items = int(os.getenv('ACTOR_MAX_PAID_DATASET_ITEMS', 0)) or None + self.is_initialized = False + self.is_getting_item_count = False + self.pushed_item_count = 0 + + async def push_data_max_aware(self, data: Union[Dict[Any, Any], List[Dict[Any, Any]]]) -> Dict[str, bool]: + # If this isn't pay-per-result, just push like normally + if not self.max_items: + await Actor.push_data(data) + return {'shouldStop': False} + + # Initialize on the first call + if not self.is_initialized and not self.is_getting_item_count: + self.is_getting_item_count = True + dataset = await Actor.open_dataset() + dataset_info = await dataset.get_info() + self.pushed_item_count = dataset_info['itemCount'] + self.is_getting_item_count = False + self.is_initialized = True + + # Others handlers will wait until initialized which should be few milliseconds + while not self.is_initialized: + await Actor.sleep(0.05) + + data_as_array = data if isinstance(data, list) else [data] + data_to_push = data_as_array[:self.max_items - self.pushed_item_count] + + if data_to_push: + # Update the state before 'await' to avoid race conditions + self.pushed_item_count += len(data_to_push) + await Actor.push_data(data_to_push) + + return {'shouldStop': self.pushed_item_count >= self.max_items} + +# Create a singleton instance +ppr_manager = PayPerResultManager() + +# Convenience function that uses the singleton +async def push_data_max_aware(data: Union[Dict[Any, Any], List[Dict[Any, Any]]]) -> Dict[str, bool]: + return await ppr_manager.push_data_max_aware(data) ``` -You can find the whole code of implementing this check in this [example](https://github.com/metalwarrior665/max-paid-items-example/blob/master/src/push-data.ts). - ### Test your Actor Test your Actor with various result volumes to determine optimal pricing. Start with minimal datasets (1-100 results) to understand your base costs and ensure the Actor works correctly with small inputs. Then test with typical usage volumes (1,000-10,000 results) to simulate real-world scenarios and identify any performance bottlenecks. From 65ce975a48a1c0e7f44d5dac177b3d75606e2f4e Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Fri, 5 Sep 2025 15:33:28 +0200 Subject: [PATCH 10/21] docs: Fix event name --- .../actors/publishing/monetize/pay_per_event.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index 96937451ec..2bcef5fc7a 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -247,9 +247,9 @@ The `eventChargeLimitReached` property checks if the current event type can be c ```js import { Actor } from 'apify'; -const chargForApiCall = async () => { +const chargForApiProductDetail = async () => { const chargeResult = await Actor.charge({ - eventName: "api-call", + eventName: "product-detail", }); return chargeResult; @@ -260,7 +260,7 @@ await Actor.init(); const main = async () => { // API call, or any other logic that you want to charge for - const chargeResult = await chargForApiCall(); + const chargeResult = await chargForApiProductDetail(); if (chargeResult.eventChargeLimitReached) { await Actor.exit(); @@ -280,8 +280,8 @@ await Actor.exit(); ```python from apify import Actor -async def charge_for_api_call(): - charge_result = await Actor.charge(event_name='api-call') +async def charge_for_api_product_detail(): + charge_result = await Actor.charge(event_name='product-detail') return charge_result @@ -290,7 +290,7 @@ async def main(): # API call, or any other logic that you want to charge for - charge_result = await charge_for_api_call() + charge_result = await charge_for_api_product_detail() if charge_result.event_charge_limit_reached: await Actor.exit() From 707fc4f54f4b6e59f859b928bac28c98748876f3 Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Fri, 5 Sep 2025 15:42:19 +0200 Subject: [PATCH 11/21] docs: Edit PPR python example --- .../platform/actors/publishing/monetize/pay_per_result.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index 9d7b324039..036066e8b9 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -118,6 +118,7 @@ export const pushDataMaxAware = async (data: Parameters[0]): ```python import os +import asyncio from apify import Actor from typing import Union, List, Dict, Any @@ -143,9 +144,9 @@ class PayPerResultManager: self.is_getting_item_count = False self.is_initialized = True - # Others handlers will wait until initialized which should be few milliseconds + # Wait until initialized while not self.is_initialized: - await Actor.sleep(0.05) + await asyncio.sleep(0.05) # 50ms data_as_array = data if isinstance(data, list) else [data] data_to_push = data_as_array[:self.max_items - self.pushed_item_count] From d5323417f18c6be6ff46b92d58a8799441c6b18a Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Mon, 8 Sep 2025 15:17:15 +0200 Subject: [PATCH 12/21] docs: First round of reviews --- .../actors/publishing/monetize/index.mdx | 17 ++++----- .../publishing/monetize/pay_per_event.mdx | 38 +++++++++---------- .../publishing/monetize/pay_per_result.mdx | 12 ++++++ .../publishing/monetize/pricing_and_costs.mdx | 8 +++- .../actors/publishing/monetize/rental.mdx | 6 +++ 5 files changed, 50 insertions(+), 31 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx index 73ddd33357..ca936e1019 100644 --- a/sources/platform/actors/publishing/monetize/index.mdx +++ b/sources/platform/actors/publishing/monetize/index.mdx @@ -30,16 +30,15 @@ For a detailed comparison of pricing models from the perspective of your users, The following table compares the two main pricing models available for monetizing your Actors: | Feature/Category | Rental pricing | Pay-per-result (PPR) | Pay-per-event (PPE) | -|-------------------------|-------------------------------|------------------------------|-------------------------------| -| Revenue scalability | Capped at monthly fee | Unlimited, scales with usage | Unlimited, scales with usage | -| AI/MCP compatibility | ❌ Not compatible | ✅ Fully compatible | ✅ Fully compatible | -| User cost predictability| Confusing (rental + usage) | Clear, transparent pricing | Clear, transparent pricing | -| Tiered pricing support | ❌ Single price only | ✅ Store discounts available | ✅ Store discounts available | -| Marketing boost* | Standard visibility | Priority store placement | Priority store placement | -| Commission opportunities| Standard 20% | Promotional 0% periods | Promotional 0% periods | -| Custom event billing | Not available | Not available | ✅ Charge for any event | +|-------------------------|-------------------------------|-------------------------------|-------------------------------| +| Revenue scalability | Capped at monthly fee | Unlimited, scales with usage | Unlimited, scales with usage | +| AI/MCP compatibility | ❌ Not compatible | ✅ Fully compatible | ✅ Fully compatible | +| User cost predictability| Confusing (rental + usage) | Clear, transparent pricing | Clear, transparent pricing | +| Store discounts | ❌ Single price only | ✅ Store discounts available | ✅ Store discounts available | +| Marketing boost* | Standard visibility | Priority store placement | Priority store placement | +| Commission opportunities| Standard 20% | Standard 20% | Promotional 0% periods | +| Custom event billing | Not available | Not available | ✅ Charge for any event | | Per-result billing | Not available | ✅ Charge per dataset item | Optional (via event) | -| Flat monthly fee | ✅ Yes | Not available | Not available | ## Setting up monetization diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index 2bcef5fc7a..c17f612036 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -14,7 +14,7 @@ import TabItem from '@theme/TabItem'; The pay-per-event pricing model offers a flexible monetization option for Actors on Apify Store. Unlike pay per result, PPE allows you to charge users based on specific events triggered programmatically by your Actor's code. -PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor by calling the [PPE charging API](/api/v2/post-charge-run), or through [JS](/sdk/js/reference/class/Actor#charge)/[Python](/sdk/python/reference/class/Actor#charge) SDK Common events include Actor start, dataset item creation, and external API calls. +PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor using the [JS](/sdk/js/reference/class/Actor#charge)/[Python](/sdk/python/reference/class/Actor#charge) SDK, or by calling the [PPE charging API](/api/v2/post-charge-run) directly. Common events include Actor start, dataset item creation, and external API calls. The details on how your cost is computed can be found in [Example of a pay-per-event pricing model](#example-of-a-pay-per-event-pricing-model). @@ -315,21 +315,16 @@ Try to limit the number of events. Fewer events make it easier for users to unde ### Make events produce visible results -Try to make your event have tangible artifacts that users can see and understand (this might not be possible when using external APIs). Each charged event should produce something concrete in the user's dataset. +For Actors that produce data, events should map to something concrete in the user's dataset or storage. -Good examples: +However, we acknowledge that some events don't produce tangible results (such as running AI workflows or processing external API calls). This flexibility is what makes pay-per-event pricing powerful. It gives you the freedom to charge for special operations, complex workflows, and unique value propositions. + +Examples: - _"scraped-product" event_: Each charge adds one product record to the dataset - _"processed-image" event_: Each charge adds one processed image to the dataset - _"extracted-review" event_: Each charge adds one review to the dataset - -Avoid charging for: - -- Internal processing steps that don't produce visible results -- API calls that don't generate user-visible data -- Setup or configuration steps - -This helps users understand exactly what they're paying for and builds trust in your pricing model. +- _"ai-analysis" event_: Each charge processes one document through an AI workflow (no tangible output, but valuable processing) ### Use idempotency keys to prevent double charges @@ -342,23 +337,24 @@ You make your Actor pay-per-event and set the following pricing: - _"actor-start" event_: $0.10 per start - _"scraped-product" event_: $0.01 per product - _"scraped-product-detail" event_: $0.05 per detail +- _"ai-analysis" event_: $0.15 per analysis During the first month, three users use your Actor: -- _User 1 (paid plan)_: Starts Actor 5 times, scrapes 1,000 products, makes 50 product details - - Charges: 5 × $0.10 + 1,000 × $0.01 + 50 × $0.05 = $0.50 + $10.00 + $2.50 = $13.00 -- _User 2 (paid plan)_: Starts Actor 2 times, scrapes 500 products, makes 20 product details - - Charges: 2 × $0.10 + 500 × $0.01 + 20 × $0.05 = $0.20 + $5.00 + $1.00 = $6.20 -- _User 3 (free plan)_: Starts Actor 1 time, scrapes 100 products, makes 5 product details - - Charges: 1 × $0.10 + 100 × $0.01 + 5 × $0.05 = $0.10 + $1.00 + $0.25 = $1.35 +- _User 1 (paid plan)_: Starts Actor 5 times, scrapes 1,000 products, makes 50 product details, runs 30 AI analyses + - Charges: 5 × $0.10 + 1,000 × $0.01 + 50 × $0.05 + 30 × $0.15 = $0.50 + $10.00 + $2.50 + $4.50 = $17.50 +- _User 2 (paid plan)_: Starts Actor 2 times, scrapes 500 products, makes 20 product details, runs 10 AI analyses + - Charges: 2 × $0.10 + 500 × $0.01 + 20 × $0.05 + 10 × $0.15 = $0.20 + $5.00 + $1.00 + $1.50 = $7.70 +- _User 3 (free plan)_: Starts Actor 1 time, scrapes 100 products, makes 5 product details, runs 3 AI analyses + - Charges: 1 × $0.10 + 100 × $0.01 + 5 × $0.05 + 3 × $0.15 = $0.10 + $1.00 + $0.25 + $0.45 = $1.80 -Let's say the underlying platform usage for the first user is $2.50, for the second $1.20, and for the third $0.30. +Let's say the underlying platform usage for the first user is $3.20, for the second $1.50, and for the third $0.40. Your profit is computed only from the first two users, since they are on Apify paid plans. The revenue breakdown is: -- _Total revenue_: $13.00 + $6.20 = $19.20 -- _Total underlying cost_: $2.50 + $1.20 = $3.70 -- _Your profit_: 80% of revenue minus costs = 0.8 × $19.20 - $3.70 = $11.66 +- _Total revenue_: $17.50 + $7.70 = $25.20 +- _Total underlying cost_: $3.20 + $1.50 = $4.70 +- _Your profit_: 80% of revenue minus costs = 0.8 × $25.20 - $4.70 = $15.46 ## PPE event names diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index 036066e8b9..6ef9a49a75 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -16,6 +16,12 @@ In this model, you set a price per 1,000 results. Users are charged based on the The details on how your cost is computed can be found in [Example of a pay-per-result pricing model](#example-of-a-pay-per-result-pricing-model). +:::tip Additional benefits + +Actors that implement pay-per-result pricing receive additional benefits, including increased visibility in the Apify Store and enhanced discoverability for users looking for monetized solutions. + +::: + ## Pay-per-result (PPR) vs. pay-per-event (PPE) Unlike PPR, which charges based on the number of results produced, PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor by calling the PPE charging API. Common events include Actor start, dataset item creation, and external API calls. @@ -175,6 +181,12 @@ Test your Actor with various result volumes to determine optimal pricing. Start Throughout all testing, monitor platform usage costs for each test run to calculate the true cost per result. This cost analysis is crucial for setting profitable pricing that covers your expenses while remaining competitive in the market. +:::tip Use Actor analytics for cost estimation + +Check the **cost per 1000 results** chart in your Actor's analytics in Apify Console. This chart is computed from all runs of both paying and free users, giving you a comprehensive view of platform usage costs across different usage patterns. Use this data to better estimate the adequate price for your Actor. + +::: + ### Push at least one "error item" to the dataset In PPR Actors, users are only charged when your Actor produces results in the dataset. If your Actor encounters invalid input or finds no results, it should still push at least one item to the dataset to ensure the user is charged for the attempt. diff --git a/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx b/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx index 67bdc4d0bd..fe7b9f7520 100644 --- a/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx +++ b/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx @@ -51,7 +51,7 @@ When you monetize your Actor in Standby mode using pay per event mode only, you ::: -## How to attract larger customers of PPE and PPR Actors +## Discount tiers and pricing strategy Each user running your PPE or PPR Actor belongs to a discount tier: @@ -65,8 +65,14 @@ While optional, we recommend offering progressively lower prices for higher disc Your platform costs are also lower for these higher tier, which helps maintain healthy profit margins. This is further detailed in the [Computing your costs for PPE and PPR Actors](#computing-your-costs-for-ppe-and-ppr-actors) section. +## Implementing discount tiers + By default, we advise against setting excessively high prices for _FREE_ tier users, as this can limit the ability to evaluate your Actor thoroughly. However, in certain situations, such as protecting your Actor from fraudulent activity or excessive use of your internal APIs, a higher price for _FREE_ tier users might be justified. During an Actor run, you can identify the user's discount tier through Actor run environment variables or by querying user data via the Apify API. This capability allows you to offer premium features or differentiated service levels to users in higher discount tiers. +## Additional benefits and enterprise tiers + +Actors that implement tiered pricing also receive additional benefits like enhanced visibility in the Apify Store, making your Actor more discoverable to potential users. + In addition to the standard tiers, Apify provides further tiers specifically for enterprise customers, including _PLATINUM_ and _DIAMOND_ tiers. If you are interested in offering enterprise-level services and attracting major clients, please contact us. diff --git a/sources/platform/actors/publishing/monetize/rental.mdx b/sources/platform/actors/publishing/monetize/rental.mdx index bba8f36255..90f9afbedc 100644 --- a/sources/platform/actors/publishing/monetize/rental.mdx +++ b/sources/platform/actors/publishing/monetize/rental.mdx @@ -7,6 +7,12 @@ sidebar_position: 1 **Learn how to monetize your Actor with the rental pricing model, offering users a free trial and a flat monthly fee, and understand how profit is calculated and the limitations of this approach.** +:::warning Rental is becoming a legacy pricing model + +Rental-priced Actors are harder to use from MCP and AI platforms. Switch to pay-per-event pricing for better adoption. + +::: + --- With the rental model, you can specify a free trial period and a monthly rental price. After the trial, users with an [Apify paid plan](https://apify.com/pricing) can continue using your Actor by paying the monthly fee. You can receive 80% of the total rental fees collected each month. From ed58c593e05e7fc25f9d1af255f1c5c129569af9 Mon Sep 17 00:00:00 2001 From: Patrik Braborec Date: Mon, 8 Sep 2025 15:32:46 +0200 Subject: [PATCH 13/21] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michał Olender <92638966+TC-MO@users.noreply.github.com> --- .../platform/actors/publishing/monetize/index.mdx | 10 +++++----- .../actors/publishing/monetize/pay_per_event.mdx | 12 ++++++------ .../actors/publishing/monetize/pay_per_result.mdx | 8 ++++---- .../actors/publishing/monetize/pricing_and_costs.mdx | 2 +- .../platform/actors/publishing/monetize/rental.mdx | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx index ca936e1019..38dd580859 100644 --- a/sources/platform/actors/publishing/monetize/index.mdx +++ b/sources/platform/actors/publishing/monetize/index.mdx @@ -18,10 +18,10 @@ Apify Store allows you to monetize your web scraping, automation and AI Agent pr Actors in Apify Store can be published under one of the following pricing models: -1. **Free**: Users can run the Actor without any additional charges beyond the platform usage costs generated by the Actor. -2. **Rental**: Users pay for the platform usage costs. However, after a trial period, they need to pay a flat monthly fee to the developer to continue using the Actor. -3. **Pay per result (PPR)**: Users don't pay for the platform usage costs. Instead, they pay the developer based on the number of results produced by the Actor. -4. **Pay per event (PPE)**: Users don't pay for the platform usage cost the Actor generates. Instead, they pay based on specific events that are programmatically triggered from the Actor's source code. These events are defined by the developer and can include actions such as generating a single result or starting an Actor. +1. _Free_: Users can run the Actor without any additional charges beyond the platform usage costs generated by the Actor. +2. _Rental_: Users pay for the platform usage costs. However, after a trial period, they need to pay a flat monthly fee to the developer to continue using the Actor. +3. _Pay per result (PPR)_: Users don't pay for the platform usage costs. Instead, they pay the developer based on the number of results produced by the Actor. +4. _Pay per event (PPE)_: Users don't pay for the platform usage cost the Actor generates. Instead, they pay based on specific events that are programmatically triggered from the Actor's source code. These events are defined by the developer and can include actions such as generating a single result or starting an Actor. For a detailed comparison of pricing models from the perspective of your users, refer to [Actors in Store](/platform/actors/running/actors-in-store) page. @@ -107,7 +107,7 @@ All metrics can be exported as JSON for custom analysis and reporting. ## Promoting your Actor -Create serach-engine-optimized descriptions and README files to improve search engine visibility. Share your Actor on multiple channels: +Create search-engine-optimized descriptions and README files to improve search engine visibility. Share your Actor on multiple channels: - Post on Reddit, Quora, and social media platforms - Create tutorial videos demonstrating key features diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index c17f612036..5b0dbf78e0 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -1,5 +1,5 @@ --- -title: Pay per event (PPE) +title: Pay per event description: Learn how to monetize your Actor with pay-per-event (PPE) pricing, charging users for specific actions like Actor starts, dataset items, or API calls, and understand how to set profitable, transparent event-based pricing. slug: /actors/publishing/monetize/pay-per-event sidebar_position: 3 @@ -114,7 +114,7 @@ await Actor.exit(); -```python +```py from apify import Actor async def charge_for_actor_start(): @@ -139,7 +139,7 @@ async def main(): :::note Actor migrations and charging -Actors can migrate between servers during execution, which restarts the process and clears memory. When using PPE charging, avoid charging the start event multiple times after a migration by checking your charging state. +Actors can migrate between servers during execution, which restarts the process and clears memory. When using PPE pricing model, avoid charging the start event multiple times after a migration by checking your charging state. ::: @@ -196,7 +196,7 @@ await Actor.exit(); -```python +```py from apify import Actor import requests @@ -237,7 +237,7 @@ async def main(): ### Respect user spending limits -Finish the Actor run once charging reaches user-configured Maximum cost per run. Apify SDKs (JS and Python) return ChargeResult that helps determine when to finish. +Finish the Actor run once charging reaches user-configured Maximum cost per run. Apify SDKs (JS and Python) return `ChargeResult` that helps determine when to finish. The `eventChargeLimitReached` property checks if the current event type can be charged more. If you have multiple event types, analyze the `chargeableWithinLimit` property to see if other events can still be charged before stopping the Actor. @@ -277,7 +277,7 @@ await Actor.exit(); -```python +```py from apify import Actor async def charge_for_api_product_detail(): diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index 6ef9a49a75..11e249c58f 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -1,5 +1,5 @@ --- -title: Pay per result (PPR) +title: Pay per result description: Learn how to monetize your Actor with pay-per-result (PPR) pricing, charging users based on the number of results produced and stored in the dataset, and understand how to set profitable, transparent result-based pricing. slug: /actors/publishing/monetize/pay-per-result sidebar_position: 2 @@ -122,7 +122,7 @@ export const pushDataMaxAware = async (data: Parameters[0]): -```python +```py import os import asyncio from apify import Actor @@ -205,9 +205,9 @@ Example scenarios: This ensures that every run generates at least one result, guaranteeing that users are charged appropriately for using your Actor. -## Example of a pay-per-result pricing model +## Example of pay-per-result pricing model -You make your Actor pay-per-result and set the price to be **$1/1,000 results**. During the first month, three users use your Actor: +You make your Actor pay-per-result and set the price to be _$1/1,000 results_. During the first month, three users use your Actor: - _User 1 (paid plan)_: Gets 50,000 results, costing them $50 - _User 2 (paid plan)_: Gets 20,000 results, costing them $20 diff --git a/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx b/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx index fe7b9f7520..b35877b839 100644 --- a/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx +++ b/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx @@ -21,7 +21,7 @@ Platform usage by _FREE_ tier users is covered by Apify and does not contribute ::: -To calculate your costs in dollars for a specific run by paying user, multiply the unit cost of each service by the quantity consumed. For example, if a _BRONZE_ tier user run uses 10 compute units (CUs) at $0.4/CU, your cost would be $4. +To calculate your costs for a specific run by paying user, multiply the unit cost of each service by the quantity consumed. For example, if a _BRONZE_ tier user run uses 10 compute units (CUs) at $0.4/CU, your cost would be $4. As highlighted in the [How to attract larger customers of PPE and PPR Actors](#how-to-attract-larger-customers-of-ppe-and-ppr-actors) section, if your Actor uses tiered pricing, the user's discount tier determines the unit costs applied to their runs. Your costs are lower for higher tiers, enabling you to offer more competitive pricing to these customers, while sustaining healthy profit margins. diff --git a/sources/platform/actors/publishing/monetize/rental.mdx b/sources/platform/actors/publishing/monetize/rental.mdx index 90f9afbedc..914031c81c 100644 --- a/sources/platform/actors/publishing/monetize/rental.mdx +++ b/sources/platform/actors/publishing/monetize/rental.mdx @@ -49,7 +49,7 @@ Based on the reasons mentioned in [Disadvantages of the rental pricing model](#d ## Example of a rental pricing model -You make your Actor rental with **7-day free trial** and then **$30/month**. During the first calendar month, three users start to use your Actor: +You make your Actor rental with _7-day free trial_ and then _$30/month_. During the first calendar month, three users start to use your Actor: - _User 1 (paid plan)_: Starts free trial on the 15th - _User 2 (paid plan)_: Starts free trial on the 25th From ea3cc39807f608365c416e2ad2866c75b8cd48e6 Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Mon, 8 Sep 2025 15:38:04 +0200 Subject: [PATCH 14/21] docs: Fix lint errors --- sources/platform/actors/publishing/monetize/pay_per_event.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index 5b0dbf78e0..a7900460c5 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -315,7 +315,7 @@ Try to limit the number of events. Fewer events make it easier for users to unde ### Make events produce visible results -For Actors that produce data, events should map to something concrete in the user's dataset or storage. +For Actors that produce data, events should map to something concrete in the user's dataset or storage. However, we acknowledge that some events don't produce tangible results (such as running AI workflows or processing external API calls). This flexibility is what makes pay-per-event pricing powerful. It gives you the freedom to charge for special operations, complex workflows, and unique value propositions. From 4870c1be9ddc73888051cb89233c65cdef0997f2 Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Mon, 8 Sep 2025 15:47:58 +0200 Subject: [PATCH 15/21] docs: PR review comments --- .../platform/actors/publishing/monetize/pay_per_event.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index a7900460c5..dc16e9fe8e 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -321,10 +321,10 @@ However, we acknowledge that some events don't produce tangible results (such as Examples: -- _"scraped-product" event_: Each charge adds one product record to the dataset -- _"processed-image" event_: Each charge adds one processed image to the dataset -- _"extracted-review" event_: Each charge adds one review to the dataset -- _"ai-analysis" event_: Each charge processes one document through an AI workflow (no tangible output, but valuable processing) +- _`scraped-product` event_: Each charge adds one product record to the dataset +- _`processed-image` event_: Each charge adds one processed image to the dataset +- _`extracted-review` event_: Each charge adds one review to the dataset +- _`ai-analysis` event_: Each charge processes one document through an AI workflow (no tangible output, but valuable processing) ### Use idempotency keys to prevent double charges From 2f7a9c69e9fca488b258f9c2d4b078b33420d04b Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Mon, 8 Sep 2025 16:52:03 +0200 Subject: [PATCH 16/21] docs: Fix another PR comments --- .../publishing/monetize/pay_per_event.mdx | 8 ++--- .../publishing/monetize/pay_per_result.mdx | 4 +-- .../publishing/monetize/pricing_and_costs.mdx | 29 +++++++++---------- .../actors/publishing/monetize/rental.mdx | 2 +- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index dc16e9fe8e..bf78206356 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -334,10 +334,10 @@ If you're not using the Apify SDKs (JS/Python), you need to handle idempotency ( You make your Actor pay-per-event and set the following pricing: -- _"actor-start" event_: $0.10 per start -- _"scraped-product" event_: $0.01 per product -- _"scraped-product-detail" event_: $0.05 per detail -- _"ai-analysis" event_: $0.15 per analysis +- _`actor-start` event_: $0.10 per start +- _`scraped-product` event_: $0.01 per product +- _`scraped-product-detail` event_: $0.05 per detail +- _`ai-analysis` event_: $0.15 per analysis During the first month, three users use your Actor: diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index 11e249c58f..5113dcb276 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -61,7 +61,7 @@ Set memory limits using `minMemoryMbytes` and `maxMemoryMbytes` in your [`actor. :::note Memory requirements for browser-based scraping -When using browser automation tools like Puppeteer or Playwright for web scraping, increase the memory limits to accommodate the browser's memory usage. +When using browser automation tools like [Puppeteer](https://pptr.dev/) or [Playwright](https://playwright.dev/) for web scraping, increase the memory limits to accommodate the browser's memory usage. ::: @@ -69,7 +69,7 @@ When using browser automation tools like Puppeteer or Playwright for web scrapin This check prevents your Actor from generating more results than the user has paid for, protecting both you and your users from unexpected costs. -The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for paid-per-result Actors. Do not exceed this limit. You can see the example implementation in the following code snippets. +The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for pay-per-results Actors. Do not exceed this limit. You can see the example implementation in the following code snippets. diff --git a/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx b/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx index b35877b839..e50d4920d7 100644 --- a/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx +++ b/sources/platform/actors/publishing/monetize/pricing_and_costs.mdx @@ -27,20 +27,20 @@ As highlighted in the [How to attract larger customers of PPE and PPR Actors](#h The following table summarizes the platform unit costs used for your cost computation across different discount tiers. -| Service | Price is per | _FREE_ | _BRONZE_ | _SILVER_ | _GOLD_ | -|:-------------------------------|:--------------|--------:|---------:|---------:|--------:| -| Compute unit | CU | $0.4 | $0.4 | $0.3 | $0.25 | -| Residential proxies | GB | $8 | $8 | $7.5 | $7 | -| SERPs proxy | 1,000 SERPs | $2.5 | $2.5 | $2 | $1.7 | -| Data transfer - external | GB | $0.2 | $0.2 | $0.19 | $0.18 | -| Data transfer - internal | GB | $0.05 | $0.05 | $0.045 | $0.04 | -| Dataset - reads | 1,000 reads | $0.0004 | $0.0004 | $0.00036 | $0.00032| -| Dataset - writes | 1,000 writes | $0.005 | $0.005 | $0.0045 | $0.004 | -| Key-value store - reads | 1,000 reads | $0.005 | $0.005 | $0.0045 | $0.004 | -| Key-value store - writes | 1,000 writes | $0.05 | $0.05 | $0.045 | $0.04 | -| Key-value store - lists | 1,000 lists | $0.05 | $0.05 | $0.045 | $0.04 | -| Request queue - reads | 1,000 reads | $0.004 | $0.004 | $0.0036 | $0.0032 | -| Request queue - writes | 1,000 writes | $0.02 | $0.02 | $0.018 | $0.016 | +| Service (unit) | _FREE_ | _BRONZE_ | _SILVER_ | _GOLD_ | +|:--------------------------------------|--------:|---------:|---------:|--------:| +| Compute unit (per CU) | $0.4 | $0.4 | $0.3 | $0.25 | +| Residential proxies (per GB) | $8 | $8 | $7.5 | $7 | +| SERPs proxy (per 1,000 SERPs) | $2.5 | $2.5 | $2 | $1.7 | +| Data transfer - external (per GB) | $0.2 | $0.2 | $0.19 | $0.18 | +| Data transfer - internal (per GB) | $0.05 | $0.05 | $0.045 | $0.04 | +| Dataset - reads (per 1,000 reads) | $0.0004 | $0.0004 | $0.00036 | $0.00032| +| Dataset - writes (per 1,000 writes) | $0.005 | $0.005 | $0.0045 | $0.004 | +| Key-value store - reads (per 1,000) | $0.005 | $0.005 | $0.0045 | $0.004 | +| Key-value store - writes (per 1,000) | $0.05 | $0.05 | $0.045 | $0.04 | +| Key-value store - lists (per 1,000) | $0.05 | $0.05 | $0.045 | $0.04 | +| Request queue - reads (per 1,000) | $0.004 | $0.004 | $0.0036 | $0.0032 | +| Request queue - writes (per 1,000) | $0.02 | $0.02 | $0.018 | $0.016 | If you decide not to offer tiered discounts on your Actor, the unit prices for _FREE_ tier apply. To offer enterprise level services and unlock even cheaper unit prices for enterprise customers, please reach out to us. @@ -50,7 +50,6 @@ When you monetize your Actor in Standby mode using pay per event mode only, you ::: - ## Discount tiers and pricing strategy Each user running your PPE or PPR Actor belongs to a discount tier: diff --git a/sources/platform/actors/publishing/monetize/rental.mdx b/sources/platform/actors/publishing/monetize/rental.mdx index 914031c81c..2935c111c7 100644 --- a/sources/platform/actors/publishing/monetize/rental.mdx +++ b/sources/platform/actors/publishing/monetize/rental.mdx @@ -41,7 +41,7 @@ The rental model, while easy to set up, is less profitable because its pricing d ### AI compatibility limitations -The growing limitation is AI compatibility. Apify's MCP server explicitly excludes rental Actors from search results, making them invisible to AI systems that dynamically select and execute tools. This significantly reduces your Actor's discoverability in AI workflows. +The growing limitation is AI compatibility. [Apify's MCP server](/platform/integrations/mcp) explicitly excludes rental Actors from search results, making them invisible to AI systems that dynamically select and execute tools. This significantly reduces your Actor's discoverability in AI workflows. ## Consider pay-per-result or pay-per-event pricing models From 347a60519f5ab6f64b7a8265a310451859efffff Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Tue, 9 Sep 2025 15:46:52 +0200 Subject: [PATCH 17/21] docs: Fix PR comments --- .../publishing/monetize/pay_per_event.mdx | 22 ++++++++--------- .../publishing/monetize/pay_per_result.mdx | 24 +++++++------------ 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index bf78206356..76e6700326 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -12,11 +12,11 @@ sidebar_position: 3 import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -The pay-per-event pricing model offers a flexible monetization option for Actors on Apify Store. Unlike pay per result, PPE allows you to charge users based on specific events triggered programmatically by your Actor's code. +The PPE pricing model offers a flexible monetization option for Actors on Apify Store. Unlike pay per result, PPE allows you to charge users based on specific events triggered programmatically by your Actor's code. PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor using the [JS](/sdk/js/reference/class/Actor#charge)/[Python](/sdk/python/reference/class/Actor#charge) SDK, or by calling the [PPE charging API](/api/v2/post-charge-run) directly. Common events include Actor start, dataset item creation, and external API calls. -The details on how your cost is computed can be found in [Example of a pay-per-event pricing model](#example-of-a-pay-per-event-pricing-model). +The details on how your cost is computed can be found in [Example of a PPE pricing model](#example-of-a-ppe-pricing-model). ## How is profit computed @@ -40,7 +40,7 @@ An Actor's negative net profit does not affect the positive profit of another Ac ::: -## How to set pricing for pay-per-event Actors +## How to set pricing for PPE Actors 1. _Understand your costs_: Analyze resource usage (e.g CPU, memory, proxies, external APIs) and identify cost drivers 1. _Define clear events_: break your Actor's functionality into measurable, chargeable events. @@ -51,7 +51,7 @@ An Actor's negative net profit does not affect the positive profit of another Ac 1. _Test your pricing_: Run your Actor and analyze cost-effectiveness using a special dataset. 1. _Communicate value_: Ensure pricing reflects the value provided and is competitive. -## Best practices for pay-per-event Actors +## Best practices for PPE Actors Use our SDKs (JS and, Python or use [`apify actor charge`](/cli/docs/next/reference#apify-actor-charge-eventname) when using our Apify CLI) to simplify PPE implementation into your Actor. This tool can handle pricing, usage tracking, idempotency keys, API errors, and, event charging via an API. @@ -77,9 +77,9 @@ When using browser automation tools like Puppeteer or Playwright for web scrapin ::: -### Charge for "Actor start" +### Charge for `Actor start` -Charge for "Actor start" to prevent users from running your Actor for free. +Charge for `Actor start` to prevent users from running your Actor for free. @@ -317,7 +317,7 @@ Try to limit the number of events. Fewer events make it easier for users to unde For Actors that produce data, events should map to something concrete in the user's dataset or storage. -However, we acknowledge that some events don't produce tangible results (such as running AI workflows or processing external API calls). This flexibility is what makes pay-per-event pricing powerful. It gives you the freedom to charge for special operations, complex workflows, and unique value propositions. +However, we acknowledge that some events don't produce tangible results (such as running AI workflows or processing external API calls). This flexibility is what makes PPE pricing powerful. It gives you the freedom to charge for special operations, complex workflows, and unique value propositions. Examples: @@ -330,9 +330,9 @@ Examples: If you're not using the Apify SDKs (JS/Python), you need to handle idempotency (ensuring the same operation produces the same result when called multiple times) manually to prevent charging the same event multiple times. -## Example of a pay-per-event pricing model +## Example of a PPE pricing model -You make your Actor pay-per-event and set the following pricing: +You make your Actor PPE and set the following pricing: - _`actor-start` event_: $0.10 per start - _`scraped-product` event_: $0.01 per product @@ -356,9 +356,9 @@ Your profit is computed only from the first two users, since they are on Apify p - _Total underlying cost_: $3.20 + $1.50 = $4.70 - _Your profit_: 80% of revenue minus costs = 0.8 × $25.20 - $4.70 = $15.46 -## PPE event names +## Event names -To implement pay-per-event pricing, you need to define specific events in your Actor code. You can retrieve the list of available pricing event names using the [Get Actor](https://apify.com/docs/api/v2/act-get) API endpoint. +To implement PPE pricing, you need to define specific events in your Actor code. You can retrieve the list of available pricing event names using the [Get Actor](https://apify.com/docs/api/v2/act-get) API endpoint. ## Next steps diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index 5113dcb276..41117e4d07 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -14,20 +14,14 @@ import TabItem from '@theme/TabItem'; In this model, you set a price per 1,000 results. Users are charged based on the number of results your Actor produces and stores in the run's default dataset. Your profit is calculated as 80% of the revenue minus platform usage costs. -The details on how your cost is computed can be found in [Example of a pay-per-result pricing model](#example-of-a-pay-per-result-pricing-model). +The details on how your cost is computed can be found in [Example of a PPR pricing model](#example-of-a-ppr-pricing-model). :::tip Additional benefits -Actors that implement pay-per-result pricing receive additional benefits, including increased visibility in the Apify Store and enhanced discoverability for users looking for monetized solutions. +Actors that implement PPR pricing receive additional benefits, including increased visibility in the Apify Store and enhanced discoverability for users looking for monetized solutions. ::: -## Pay-per-result (PPR) vs. pay-per-event (PPE) - -Unlike PPR, which charges based on the number of results produced, PPE lets you define pricing for individual events. You can charge for specific events directly from your Actor by calling the PPE charging API. Common events include Actor start, dataset item creation, and external API calls. - -If you're interested in learning more about PPE, check out the [Pay per event (PPE)](/platform/actors/publishing/monetize/pay-per-event) section. - ## How is profit computed Your profit is calculated from the mentioned formula: @@ -37,11 +31,11 @@ Your profit is calculated from the mentioned formula: where: - _Revenue_: The amount charged for results via the PPR pricing API or through JS/Python SDK. You receive 80% of this revenue. -- _Platform costs_: The underlying platform usage costs for running the Actor, calculated in the same way as for PPE. For more details, visit the [Example of a pay-per-result pricing model](#example-of-a-pay-per-result-pricing-model) section. +- _Platform costs_: The underlying platform usage costs for running the Actor, calculated in the same way as for PPE. For more details, visit the [Example of a PPR pricing model](#example-of-a-ppr-pricing-model) section. Only revenue and cost for Apify customers on paid plans are taken into consideration when computing your profit. Users on free plans are not reflected there. -## Best practices for pay-per-result Actors +## Best practices for PPR Actors To ensure profitability, check the following best practices. @@ -69,7 +63,7 @@ When using browser automation tools like [Puppeteer](https://pptr.dev/) or [Play This check prevents your Actor from generating more results than the user has paid for, protecting both you and your users from unexpected costs. -The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for pay-per-results Actors. Do not exceed this limit. You can see the example implementation in the following code snippets. +The `ACTOR_MAX_PAID_DATASET_ITEMS` environment variable contains the user-set limit on returned results for PPR Actors. Do not exceed this limit. You can see the example implementation in the following code snippets. @@ -85,7 +79,7 @@ let isGettingItemCount = false; let pushedItemCount = 0; export const pushDataMaxAware = async (data: Parameters[0]): Promise<{ shouldStop: boolean }> => { - // If this isn't pay-per-result, just push like normallyå + // If this isn't PPR, just push like normally if (!MAX_ITEMS) { await Actor.pushData(data); return { shouldStop: false }; @@ -136,7 +130,7 @@ class PayPerResultManager: self.pushed_item_count = 0 async def push_data_max_aware(self, data: Union[Dict[Any, Any], List[Dict[Any, Any]]]) -> Dict[str, bool]: - # If this isn't pay-per-result, just push like normally + # If this isn't PPR, just push like normally if not self.max_items: await Actor.push_data(data) return {'shouldStop': False} @@ -205,9 +199,9 @@ Example scenarios: This ensures that every run generates at least one result, guaranteeing that users are charged appropriately for using your Actor. -## Example of pay-per-result pricing model +## Example of PPR pricing model -You make your Actor pay-per-result and set the price to be _$1/1,000 results_. During the first month, three users use your Actor: +You make your Actor PPR and set the price to be _$1/1,000 results_. During the first month, three users use your Actor: - _User 1 (paid plan)_: Gets 50,000 results, costing them $50 - _User 2 (paid plan)_: Gets 20,000 results, costing them $20 From bcde3193f470b4b52cb7106f7ba9f76fe363056d Mon Sep 17 00:00:00 2001 From: patrikbraborec Date: Wed, 10 Sep 2025 15:43:57 +0200 Subject: [PATCH 18/21] docs: Fix PR comments --- sources/platform/actors/publishing/monetize/index.mdx | 2 +- .../actors/publishing/monetize/pay_per_event.mdx | 10 ++++++++-- sources/platform/actors/publishing/monetize/rental.mdx | 6 ------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx index 38dd580859..42a0e6355b 100644 --- a/sources/platform/actors/publishing/monetize/index.mdx +++ b/sources/platform/actors/publishing/monetize/index.mdx @@ -35,7 +35,7 @@ The following table compares the two main pricing models available for monetizin | AI/MCP compatibility | ❌ Not compatible | ✅ Fully compatible | ✅ Fully compatible | | User cost predictability| Confusing (rental + usage) | Clear, transparent pricing | Clear, transparent pricing | | Store discounts | ❌ Single price only | ✅ Store discounts available | ✅ Store discounts available | -| Marketing boost* | Standard visibility | Priority store placement | Priority store placement | +| Marketing boost | Standard visibility | Priority store placement | Priority store placement | | Commission opportunities| Standard 20% | Standard 20% | Promotional 0% periods | | Custom event billing | Not available | Not available | ✅ Charge for any event | | Per-result billing | Not available | ✅ Charge per dataset item | Optional (via event) | diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index 76e6700326..930af7fd5c 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -53,7 +53,7 @@ An Actor's negative net profit does not affect the positive profit of another Ac ## Best practices for PPE Actors -Use our SDKs (JS and, Python or use [`apify actor charge`](/cli/docs/next/reference#apify-actor-charge-eventname) when using our Apify CLI) to simplify PPE implementation into your Actor. This tool can handle pricing, usage tracking, idempotency keys, API errors, and, event charging via an API. +Use our SDKs ([JS](/sdk/js/) and, [Python](/sdk/python/) or use [`apify actor charge`](/cli/docs/next/reference#apify-actor-charge-eventname) when using our Apify CLI) to simplify PPE implementation into your Actor. This tool can handle pricing, usage tracking, idempotency keys, API errors, and, event charging via an API. You can also choose not to use it, but then you must handle API integration and possible edge cases manually. @@ -237,7 +237,7 @@ async def main(): ### Respect user spending limits -Finish the Actor run once charging reaches user-configured Maximum cost per run. Apify SDKs (JS and Python) return `ChargeResult` that helps determine when to finish. +Finish the Actor run once charging reaches user-configured maximum cost per run. Apify SDKs (JS and Python) return `ChargeResult` that helps determine when to finish. The `eventChargeLimitReached` property checks if the current event type can be charged more. If you have multiple event types, analyze the `chargeableWithinLimit` property to see if other events can still be charged before stopping the Actor. @@ -326,6 +326,12 @@ Examples: - _`extracted-review` event_: Each charge adds one review to the dataset - _`ai-analysis` event_: Each charge processes one document through an AI workflow (no tangible output, but valuable processing) +:::note Additional context + +You can display a status message or push a record to the dataset to inform users about non-data actions performed by your Actor. This helps users understand what actions were charged for, even if those actions do not produce tangible output. + +::: + ### Use idempotency keys to prevent double charges If you're not using the Apify SDKs (JS/Python), you need to handle idempotency (ensuring the same operation produces the same result when called multiple times) manually to prevent charging the same event multiple times. diff --git a/sources/platform/actors/publishing/monetize/rental.mdx b/sources/platform/actors/publishing/monetize/rental.mdx index 2935c111c7..5cf8ce85ca 100644 --- a/sources/platform/actors/publishing/monetize/rental.mdx +++ b/sources/platform/actors/publishing/monetize/rental.mdx @@ -7,12 +7,6 @@ sidebar_position: 1 **Learn how to monetize your Actor with the rental pricing model, offering users a free trial and a flat monthly fee, and understand how profit is calculated and the limitations of this approach.** -:::warning Rental is becoming a legacy pricing model - -Rental-priced Actors are harder to use from MCP and AI platforms. Switch to pay-per-event pricing for better adoption. - -::: - --- With the rental model, you can specify a free trial period and a monthly rental price. After the trial, users with an [Apify paid plan](https://apify.com/pricing) can continue using your Actor by paying the monthly fee. You can receive 80% of the total rental fees collected each month. From 4decc5422378d9bc4650e36a7bada9ac693a5430 Mon Sep 17 00:00:00 2001 From: Patrik Braborec Date: Wed, 10 Sep 2025 15:47:42 +0200 Subject: [PATCH 19/21] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michał Olender <92638966+TC-MO@users.noreply.github.com> --- sources/platform/actors/publishing/monetize/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx index 42a0e6355b..087e35ab53 100644 --- a/sources/platform/actors/publishing/monetize/index.mdx +++ b/sources/platform/actors/publishing/monetize/index.mdx @@ -29,7 +29,7 @@ For a detailed comparison of pricing models from the perspective of your users, The following table compares the two main pricing models available for monetizing your Actors: -| Feature/Category | Rental pricing | Pay-per-result (PPR) | Pay-per-event (PPE) | +| Feature/Category | Rental | Pay-per-result (PPR) | Pay-per-event (PPE) | |-------------------------|-------------------------------|-------------------------------|-------------------------------| | Revenue scalability | Capped at monthly fee | Unlimited, scales with usage | Unlimited, scales with usage | | AI/MCP compatibility | ❌ Not compatible | ✅ Fully compatible | ✅ Fully compatible | From 3096c2f6c91c668cc1f8ef26f9aadc3cbb2f5917 Mon Sep 17 00:00:00 2001 From: Patrik Braborec Date: Wed, 10 Sep 2025 15:47:52 +0200 Subject: [PATCH 20/21] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michał Olender <92638966+TC-MO@users.noreply.github.com> --- sources/platform/actors/publishing/monetize/index.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx index 087e35ab53..3a369a751f 100644 --- a/sources/platform/actors/publishing/monetize/index.mdx +++ b/sources/platform/actors/publishing/monetize/index.mdx @@ -19,9 +19,9 @@ Apify Store allows you to monetize your web scraping, automation and AI Agent pr Actors in Apify Store can be published under one of the following pricing models: 1. _Free_: Users can run the Actor without any additional charges beyond the platform usage costs generated by the Actor. -2. _Rental_: Users pay for the platform usage costs. However, after a trial period, they need to pay a flat monthly fee to the developer to continue using the Actor. -3. _Pay per result (PPR)_: Users don't pay for the platform usage costs. Instead, they pay the developer based on the number of results produced by the Actor. -4. _Pay per event (PPE)_: Users don't pay for the platform usage cost the Actor generates. Instead, they pay based on specific events that are programmatically triggered from the Actor's source code. These events are defined by the developer and can include actions such as generating a single result or starting an Actor. +1. _Rental_: Users pay for the platform usage costs. However, after a trial period, they need to pay a flat monthly fee to the developer to continue using the Actor. +1. _Pay per result (PPR)_: Users don't pay for the platform usage costs. Instead, they pay the developer based on the number of results produced by the Actor. +1. _Pay per event (PPE)_: Users don't pay for the platform usage cost the Actor generates. Instead, they pay based on specific events that are programmatically triggered from the Actor's source code. These events are defined by the developer and can include actions such as generating a single result or starting an Actor. For a detailed comparison of pricing models from the perspective of your users, refer to [Actors in Store](/platform/actors/running/actors-in-store) page. From 99ff118128ff75857c06642d73a37bf5a17ef616 Mon Sep 17 00:00:00 2001 From: Patrik Braborec Date: Wed, 10 Sep 2025 15:48:32 +0200 Subject: [PATCH 21/21] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michał Olender <92638966+TC-MO@users.noreply.github.com> --- sources/platform/actors/publishing/monetize/index.mdx | 2 +- sources/platform/actors/publishing/monetize/pay_per_event.mdx | 4 ++-- .../platform/actors/publishing/monetize/pay_per_result.mdx | 2 +- sources/platform/actors/publishing/monetize/rental.mdx | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx index 3a369a751f..5e0d8d9e1d 100644 --- a/sources/platform/actors/publishing/monetize/index.mdx +++ b/sources/platform/actors/publishing/monetize/index.mdx @@ -33,7 +33,7 @@ The following table compares the two main pricing models available for monetizin |-------------------------|-------------------------------|-------------------------------|-------------------------------| | Revenue scalability | Capped at monthly fee | Unlimited, scales with usage | Unlimited, scales with usage | | AI/MCP compatibility | ❌ Not compatible | ✅ Fully compatible | ✅ Fully compatible | -| User cost predictability| Confusing (rental + usage) | Clear, transparent pricing | Clear, transparent pricing | +| User cost predictability| Unpredictable (rental + usage) | Predictable | Predictable | | Store discounts | ❌ Single price only | ✅ Store discounts available | ✅ Store discounts available | | Marketing boost | Standard visibility | Priority store placement | Priority store placement | | Commission opportunities| Standard 20% | Standard 20% | Promotional 0% periods | diff --git a/sources/platform/actors/publishing/monetize/pay_per_event.mdx b/sources/platform/actors/publishing/monetize/pay_per_event.mdx index 930af7fd5c..710c7a793a 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -145,7 +145,7 @@ Actors can migrate between servers during execution, which restarts the process ### Charge for invalid input -Charge for things like URLs that appear valid but lead to errors (like 404s) since you actually had to open the page to discover the error. Return error items with proper error codes and messages instead of failing the entire Actor run. +Charge for things like URLs that appear valid but lead to errors (like 404s) since you had to open the page to discover the error. Return error items with proper error codes and messages instead of failing the entire Actor run. @@ -317,7 +317,7 @@ Try to limit the number of events. Fewer events make it easier for users to unde For Actors that produce data, events should map to something concrete in the user's dataset or storage. -However, we acknowledge that some events don't produce tangible results (such as running AI workflows or processing external API calls). This flexibility is what makes PPE pricing powerful. It gives you the freedom to charge for special operations, complex workflows, and unique value propositions. +However, we acknowledge that some events don't produce tangible results (such as running AI workflows or processing external API calls). This flexibility gives you the freedom to charge for special operations, complex workflows, and unique value propositions. Examples: diff --git a/sources/platform/actors/publishing/monetize/pay_per_result.mdx b/sources/platform/actors/publishing/monetize/pay_per_result.mdx index 41117e4d07..09ceea1331 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -18,7 +18,7 @@ The details on how your cost is computed can be found in [Example of a PPR prici :::tip Additional benefits -Actors that implement PPR pricing receive additional benefits, including increased visibility in the Apify Store and enhanced discoverability for users looking for monetized solutions. +Actors that implement PPR pricing receive additional benefits, including increased visibility in Apify Store and enhanced discoverability for users looking for monetized solutions. ::: diff --git a/sources/platform/actors/publishing/monetize/rental.mdx b/sources/platform/actors/publishing/monetize/rental.mdx index 5cf8ce85ca..204cd1d74d 100644 --- a/sources/platform/actors/publishing/monetize/rental.mdx +++ b/sources/platform/actors/publishing/monetize/rental.mdx @@ -27,7 +27,7 @@ Only revenue and cost for Apify customers on paid plans are taken into considera ### User cost confusion -Users consistently report confusion about rental pricing because they pay both the monthly rental fee AND platform usage costs. A user might see an Actor priced at $20/month, only to discover their actual costs are $35-50 depending on usage. This can create confusion about total costs and make budgeting more difficult. +Users consistently report confusion about rental pricing because they pay both the _monthly rental fee and platform usage costs_. A user might see an Actor priced at $20/month, only to discover their actual costs are $35-50 depending on usage. This can create confusion about total costs and make budgeting more difficult. ### Limited revenue scalability @@ -39,7 +39,7 @@ The growing limitation is AI compatibility. [Apify's MCP server](/platform/integ ## Consider pay-per-result or pay-per-event pricing models -Based on the reasons mentioned in [Disadvantages of the rental pricing model](#disadvantages-of-the-rental-pricing-model), we recommend using the [pay-per-result](/platform/actors/publishing/monetize/pay-per-result) or [pay-per-event](/platform/actors/publishing/monetize/pay-per-event) models instead. +We recommend using the [pay-per-result](/platform/actors/publishing/monetize/pay-per-result) or [pay-per-event](/platform/actors/publishing/monetize/pay-per-event) models instead. ## Example of a rental pricing model