diff --git a/apify-api/openapi/components/schemas/actors/UpdateActorRequest.yaml b/apify-api/openapi/components/schemas/actors/UpdateActorRequest.yaml index 67fe295422..46a67727f2 100644 --- a/apify-api/openapi/components/schemas/actors/UpdateActorRequest.yaml +++ b/apify-api/openapi/components/schemas/actors/UpdateActorRequest.yaml @@ -50,3 +50,24 @@ properties: oneOf: - nullable: true - $ref: ./DefaultRunOptions.yaml + taggedBuilds: + type: object + description: | + Object containing the Actor's tagged builds, where the key is the tag name (e.g., _latest_) and the value is an object containing the build ID. + The object you provide will completely overwrite all existing tagged builds for the Actor. + + - To create or reassign a tag: Include it in the object with the desired `buildId`. + - To remove a specific tag: Submit the object without that tag's key. + - To remove all tags: Provide an empty object: `{}`. + - If this field is omitted or `null`, the existing tags will not be changed. + nullable: true + additionalProperties: + type: object + required: + - buildId + properties: + buildId: + type: string + example: + latest: + buildId: z2EryhbfhgSyqj6Hn diff --git a/apify-api/openapi/paths/actor-runs/actor-runs@{runId}@charge.yaml b/apify-api/openapi/paths/actor-runs/actor-runs@{runId}@charge.yaml index 68e533057a..3f54eaaa80 100644 --- a/apify-api/openapi/paths/actor-runs/actor-runs@{runId}@charge.yaml +++ b/apify-api/openapi/paths/actor-runs/actor-runs@{runId}@charge.yaml @@ -7,6 +7,12 @@ post: The event you are charging for must be one of the configured events in your Actor. If the Actor is not set up as pay per event, or if the event is not configured, the endpoint will return an error. The endpoint must be called from the Actor run itself, with the same API token that the run was started with. + :::info Learn more about pay-per-event pricing + + For more details about pay-per-event (PPE) pricing, refer to our [PPE documentation](/platform/actors/publishing/monetize/pay-per-event). + + ::: + operationId: PostChargeRun parameters: - name: runId diff --git a/apify-api/openapi/paths/datasets/datasets@{datasetId}@items.yaml b/apify-api/openapi/paths/datasets/datasets@{datasetId}@items.yaml index f2dda00bcc..bde66cf2c9 100644 --- a/apify-api/openapi/paths/datasets/datasets@{datasetId}@items.yaml +++ b/apify-api/openapi/paths/datasets/datasets@{datasetId}@items.yaml @@ -367,6 +367,14 @@ get: schema: type: boolean example: false + - name: signature + in: query + description: Signature used to access the items. + required: false + style: simple + schema: + type: string + example: 2wTI46Bg8qWQrV7tavlPI responses: '200': description: '' diff --git a/apify-api/openapi/paths/key-value-stores/key-value-stores@{storeId}@keys.yaml b/apify-api/openapi/paths/key-value-stores/key-value-stores@{storeId}@keys.yaml index 6dde0abd91..6c0335a230 100644 --- a/apify-api/openapi/paths/key-value-stores/key-value-stores@{storeId}@keys.yaml +++ b/apify-api/openapi/paths/key-value-stores/key-value-stores@{storeId}@keys.yaml @@ -48,6 +48,14 @@ get: schema: type: string example: post-images- + - name: signature + in: query + description: Signature used to access the keys. + required: false + style: simple + schema: + type: string + example: 2wTI46Bg8qWQrV7tavlPI responses: '200': description: '' diff --git a/apify-api/openapi/paths/key-value-stores/key-value-stores@{storeId}@records@{recordKey}.yaml b/apify-api/openapi/paths/key-value-stores/key-value-stores@{storeId}@records@{recordKey}.yaml index 38feffc9b1..85a414ad69 100644 --- a/apify-api/openapi/paths/key-value-stores/key-value-stores@{storeId}@records@{recordKey}.yaml +++ b/apify-api/openapi/paths/key-value-stores/key-value-stores@{storeId}@records@{recordKey}.yaml @@ -32,6 +32,14 @@ get: schema: type: string example: someKey + - name: signature + in: query + description: Signature used to access the record. + required: false + style: simple + schema: + type: string + example: 2wTI46Bg8qWQrV7tavlPI responses: '200': description: '' diff --git a/package-lock.json b/package-lock.json index 25349a36bf..e30fd52563 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,51 +21,39 @@ "@docusaurus/preset-classic": "^3.8.1", "@docusaurus/theme-common": "^3.8.1", "@docusaurus/theme-mermaid": "^3.8.1", - "@docusaurus/utils": "^3.8.1", "@giscus/react": "^3.0.0", - "@mdx-js/react": "^3.0.1", "@redocly/cli": "^1.27.1", "@signalwire/docusaurus-plugin-llms-txt": "^1.2.1", - "ajv": "^8.17.1", "clsx": "^2.0.0", "docusaurus-plugin-image-zoom": "^3.0.1", "docusaurus-plugin-openapi-docs": "^4.3.7", "docusaurus-theme-openapi-docs": "^4.3.7", - "form-data": "^4.0.0", "github-buttons": "^2.28.0", "postcss-preset-env": "^10.0.0", "prism-react-renderer": "^2.4.0", "prop-types": "^15.8.1", - "proxy-from-env": "^1.1.0", "raw-loader": "^4.0.2", "react": "^19.1.0", "react-dom": "^19.1.0", "react-github-btn": "^1.4.0", - "search-insights": "2.17.3", "styled-components": "6.1.19", "unist-util-visit": "^5.0.0" }, "devDependencies": { "@apify/eslint-config": "^1.0.0", "@apify/tsconfig": "^0.1.0", - "@rsbuild/plugin-styled-components": "^1.1.0", "@types/react": "^19.0.0", "babel-plugin-styled-components": "^2.1.4", "cross-env": "^7.0.3", "eslint": "^9.32.0", - "eslint-plugin-json": "^4.0.1", - "eslint-plugin-markdown": "^5.1.0", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^5.2.0", - "fs-extra": "^11.1.1", "globals": "^16.0.0", - "globby": "^14.0.0", "markdownlint": "^0.38.0", "markdownlint-cli": "^0.45.0", "patch-package": "^8.0.0", "path-browserify": "^1.0.1", "rimraf": "^6.0.0", - "typescript": "5.9.2", + "typescript": "5.9.3", "typescript-eslint": "^8.38.0" }, "engines": { @@ -6405,24 +6393,6 @@ } } }, - "node_modules/@rsbuild/plugin-styled-components": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@rsbuild/plugin-styled-components/-/plugin-styled-components-1.4.1.tgz", - "integrity": "sha512-M3RRoQdDDy8l8lv323TrCst2/bdB2nd0GtAApJ6iOIwkGsWKuIlLI2l2TBgIrf3kHch9i4WvYFaVEA/j65tGCA==", - "dev": true, - "dependencies": { - "@swc/plugin-styled-components": "^9.0.2", - "reduce-configs": "^1.1.0" - }, - "peerDependencies": { - "@rsbuild/core": "^1.4.0-beta.4 || ^1.4.0" - }, - "peerDependenciesMeta": { - "@rsbuild/core": { - "optional": true - } - } - }, "node_modules/@rspack/binding": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.5.6.tgz", @@ -6943,18 +6913,6 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/@sindresorhus/merge-streams": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", - "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@slorber/remark-comment": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", @@ -7578,15 +7536,6 @@ "node": ">=10" } }, - "node_modules/@swc/plugin-styled-components": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@swc/plugin-styled-components/-/plugin-styled-components-9.1.0.tgz", - "integrity": "sha512-c0eVq3KLZq614zMRu3HcJ9BR/2ZFEn4j42Oyo3zsKxiMP2w33CQOAO4IqQ+BhK8EKnpIptbpGEGfBsIF7H2U4w==", - "dev": true, - "dependencies": { - "@swc/counter": "^0.1.3" - } - }, "node_modules/@swc/types": { "version": "0.1.25", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz", @@ -9779,26 +9728,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/charset": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", @@ -12554,35 +12483,6 @@ "semver": "bin/semver.js" } }, - "node_modules/eslint-plugin-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-4.0.1.tgz", - "integrity": "sha512-3An5ISV5dq/kHfXdNyY5TUe2ONC3yXFSkLX2gu+W8xAhKhfvrRvkSAeKXCxZqZ0KJLX15ojBuLPyj+UikQMkOA==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21", - "vscode-json-languageservice": "^4.1.6" - }, - "engines": { - "node": ">=18.0" - } - }, - "node_modules/eslint-plugin-markdown": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-5.1.0.tgz", - "integrity": "sha512-SJeyKko1K6GwI0AN6xeCDToXDkfKZfXcexA6B+O2Wr2btUS9GrC+YgwSyVli5DJnctUHjFXcQ2cqTaAmVoLi2A==", - "deprecated": "Please use @eslint/markdown instead", - "dev": true, - "dependencies": { - "mdast-util-from-markdown": "^0.8.5" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8" - } - }, "node_modules/eslint-plugin-react": { "version": "7.37.5", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", @@ -12615,18 +12515,6 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -13904,47 +13792,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", - "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", - "dev": true, - "dependencies": { - "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.3", - "ignore": "^7.0.3", - "path-type": "^6.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/globby/node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -15305,30 +15152,6 @@ "node": ">= 10" } }, - "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, - "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -15504,16 +15327,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -15596,16 +15409,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", @@ -17226,72 +17029,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mdast-util-from-markdown": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", - "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", - "dev": true, - "dependencies": { - "@types/mdast": "^3.0.0", - "mdast-util-to-string": "^2.0.0", - "micromark": "~2.11.0", - "parse-entities": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-from-markdown/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "dev": true - }, - "node_modules/mdast-util-from-markdown/node_modules/mdast-util-to-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-from-markdown/node_modules/micromark": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", - "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "debug": "^4.0.0", - "parse-entities": "^2.0.0" - } - }, - "node_modules/mdast-util-from-markdown/node_modules/unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "dev": true, - "dependencies": { - "@types/unist": "^2.0.2" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/mdast-util-frontmatter": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", @@ -22762,34 +22499,6 @@ "node": ">=6" } }, - "node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, - "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-entities/node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -26205,12 +25914,6 @@ "node": ">=8.0.0" } }, - "node_modules/reduce-configs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/reduce-configs/-/reduce-configs-1.1.1.tgz", - "integrity": "sha512-EYtsVGAQarE8daT54cnaY1PIknF2VB78ug6Zre2rs36EsJfC40EG6hmTU2A2P1ZuXnKAt2KI0fzOGHcX7wzdPw==", - "dev": true - }, "node_modules/redux": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", @@ -27538,11 +27241,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/search-insights": { - "version": "2.17.3", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", - "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==" - }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -28115,18 +27813,6 @@ "node": ">=8" } }, - "node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/slugify": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", @@ -29276,9 +28962,9 @@ } }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -29409,18 +29095,6 @@ "node": ">=4" } }, - "node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/unified": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", @@ -30004,19 +29678,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vscode-json-languageservice": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", - "integrity": "sha512-xGmv9QIWs2H8obGbWg+sIPI/3/pFgj/5OWBhNzs00BkYQ9UaB2F6JJaGB/2/YOZJ3BvLXQTC4Q7muqU25QgAhA==", - "dev": true, - "dependencies": { - "jsonc-parser": "^3.0.0", - "vscode-languageserver-textdocument": "^1.0.3", - "vscode-languageserver-types": "^3.16.0", - "vscode-nls": "^5.0.0", - "vscode-uri": "^3.0.3" - } - }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -30055,12 +29716,6 @@ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" }, - "node_modules/vscode-nls": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-5.2.0.tgz", - "integrity": "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==", - "dev": true - }, "node_modules/vscode-uri": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", diff --git a/package.json b/package.json index 64880109f7..cc1e3311de 100644 --- a/package.json +++ b/package.json @@ -46,24 +46,18 @@ "devDependencies": { "@apify/eslint-config": "^1.0.0", "@apify/tsconfig": "^0.1.0", - "@rsbuild/plugin-styled-components": "^1.1.0", "@types/react": "^19.0.0", "babel-plugin-styled-components": "^2.1.4", "cross-env": "^7.0.3", "eslint": "^9.32.0", - "eslint-plugin-json": "^4.0.1", - "eslint-plugin-markdown": "^5.1.0", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^5.2.0", - "fs-extra": "^11.1.1", "globals": "^16.0.0", - "globby": "^14.0.0", "markdownlint": "^0.38.0", "markdownlint-cli": "^0.45.0", "patch-package": "^8.0.0", "path-browserify": "^1.0.1", "rimraf": "^6.0.0", - "typescript": "5.9.2", + "typescript": "5.9.3", "typescript-eslint": "^8.38.0" }, "dependencies": { @@ -75,27 +69,21 @@ "@docusaurus/preset-classic": "^3.8.1", "@docusaurus/theme-common": "^3.8.1", "@docusaurus/theme-mermaid": "^3.8.1", - "@docusaurus/utils": "^3.8.1", "@giscus/react": "^3.0.0", - "@mdx-js/react": "^3.0.1", "@redocly/cli": "^1.27.1", "@signalwire/docusaurus-plugin-llms-txt": "^1.2.1", - "ajv": "^8.17.1", "clsx": "^2.0.0", "docusaurus-plugin-image-zoom": "^3.0.1", "docusaurus-plugin-openapi-docs": "^4.3.7", "docusaurus-theme-openapi-docs": "^4.3.7", - "form-data": "^4.0.0", "github-buttons": "^2.28.0", "postcss-preset-env": "^10.0.0", "prism-react-renderer": "^2.4.0", "prop-types": "^15.8.1", - "proxy-from-env": "^1.1.0", "raw-loader": "^4.0.2", "react": "^19.1.0", "react-dom": "^19.1.0", "react-github-btn": "^1.4.0", - "search-insights": "2.17.3", "styled-components": "6.1.19", "unist-util-visit": "^5.0.0" }, diff --git a/sources/academy/ai/ai-agents.mdx b/sources/academy/ai/ai-agents.mdx index 4e53884a28..8ccea0a205 100644 --- a/sources/academy/ai/ai-agents.mdx +++ b/sources/academy/ai/ai-agents.mdx @@ -251,6 +251,12 @@ Common issues and solutions: Apify's pay-per-event (PPE) pricing model allows charging users based on specific triggered events through the API or SDKs. +:::info How pay-per-event pricing works + +If you want more details about PPE pricing, refer to our [PPE documentation](/platform/actors/publishing/monetize/pay-per-event). + +::: + ### Step 1: Define chargeable events You can configure charges for events like the Actor starting, a task completing successfully, or custom events such as specific API calls. diff --git a/sources/academy/platform/get_most_of_actors/store_basics/how_actor_monetization_works.md b/sources/academy/platform/get_most_of_actors/store_basics/how_actor_monetization_works.md index c7e986d1df..d5a0266938 100644 --- a/sources/academy/platform/get_most_of_actors/store_basics/how_actor_monetization_works.md +++ b/sources/academy/platform/get_most_of_actors/store_basics/how_actor_monetization_works.md @@ -33,7 +33,11 @@ Monetizing your Actor on the Apify platform involves several key steps: - 2nd user starts their trial but pays next month. - 3rd user on a free plan finishes the trial without upgrading to a paid plan and can’t use the Actor further. -Learn more about the rental pricing model in our [documentation](/platform/actors/publishing/monetize#rental-pricing-model). +:::info Rental pricing details + +If you want more details about rental pricing, refer to our [rental pricing documentation](/platform/actors/publishing/monetize/rental). + +::: ### Pay-per-result pricing model @@ -49,7 +53,11 @@ Learn more about the rental pricing model in our [documentation](/platform/actor - Dataset storage: $1 per 1,000 GB-hours - _Example_: you set a price of $1 per 1,000 results. Two users generate 50,000 and 20,000 results, paying $50 and $20, respectively. If the platform usage costs are $5 and $2, your profit is $49. -Learn more about the pay-per-result pricing model in our [documentation](/platform/actors/publishing/monetize#pay-per-result-pricing-model). +:::info Pay-per-result details + +If you want more details about PPR pricing, refer to our [PPR documentation](/platform/actors/publishing/monetize/pay-per-result). + +::: ### Pay-per-event pricing model @@ -77,7 +85,11 @@ Learn more about the pay-per-result pricing model in our [documentation](/platfo - This comes up to $1.625 of total revenue - That means if platform usage costs are $0.365 for user A and $0.162 for user B your profit is $4.748 -Learn more about the pay-per-event pricing model in our [documentation](/platform/actors/publishing/monetize#pay-per-event-pricing-model). +:::info Pay-per-event details + +If you want more details about PPE pricing, refer to our [PPE documentation](/platform/actors/publishing/monetize/pay-per-event). + +::: ## Setting up monetization @@ -104,7 +116,7 @@ The easiest way to understand your tool's value is to look around. Are there sim Try competitor tools yourself (to assess the value and the quality they provide), check their SEO (to see how much traffic they get), and note ballpark figures. Think about what your Actor can do that competitors might be missing. -Also, remember that your Actor is a package deal with the Apify platform. So all the platform's features automatically transfer onto your Actor and its value. Scheduling, monitoring runs, ways of exporting data, proxies, and integrations can all add value to your Actor (on top of its own functionalities). Be sure to factor this into your tool's value proposition and communicate that to the potential user. +Also, remember that your Actor is a package deal with the Apify platform. All the platform's features automatically transfer onto your Actor and its value. Scheduling, monitoring runs, ways of exporting data, proxies, and integrations can all add value to your Actor (on top of its own functionalities). Be sure to factor this into your tool's value proposition and communicate that to the potential user. ### Do research in Apify Store @@ -114,13 +126,19 @@ Learn more about what makes a good readme here: [How to create an Actor README]( ### Rental, pay-per-result (PPR), or pay-per-event (PPE) -Rental pricing is technically easier: you set the rental fee, and the user covers their CU usage. So all you have to define is how much you want to charge the users. With pay-per-result, you’ll need to include both CU usage and your margin. So you have to calculate how much the average run is going to cost for the user + define how much you want to charge them. +Rental pricing allows you to charge a monthly fee for your Actor and users cover their own compute usage. + +Pay-per-result (PPR) charges users based on the number of items your Actor adds to the dataset. This model works best when each dataset item represents clear value to the user - like scraped product listings, extracted contact information, or processed documents. -To figure out the average cost per run for users, just run a few test runs and look at the statistics in the Actor [**Analytics**](https://console.apify.com/actors?tab=analytics) tab. +Pay-per-event (PPE) gives you the most flexibility and growth potential. You can charge for any meaningful event your Actor performs (for example, page scraped, browser page opened, or an external API call). This makes costs predictable for users, lets you model value precisely, and is fully compatible with AI and MCP-based integrations. -From an average user's perspective, pay-per-result is often easier to grasp — $25 for a thousand pages, $5 for a thousand videos, $1 for a thousand images, etc. It gives users a clearer idea of what they’re paying for and allows them to estimate faster. But rental pricing has its fans, too — if your tool provides high value, users will come. +:::tip Additional benefits + +Actors that implement PPE receive additional benefits, including increased visibility in Apify Store and enhanced discoverability. + +::: -Pay-per-event (PPE) lets you define pricing for individual events. You can charge for specific events directly from your Actor by calling our PPE charging API. The most common events will most likely be Actor start, dataset item, external API calls, etc. PPE is great for users who want to optimize their costs and value transparency. PPE is also a fairer pricing model for integration and AI-driven use cases, where dataset-based pricing doesn’t make sense. +To estimate pricing, run a few test runs and review the statistics in the Actor [**Analytics**](https://console.apify.com/actors?tab=analytics) tab. ### Adapt when needed diff --git a/sources/platform/actors/publishing/monetize/index.mdx b/sources/platform/actors/publishing/monetize/index.mdx index 5e0d8d9e1d..78a9c3ddfc 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| 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 | +| Marketing boost | Standard visibility | Standard visibility | 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 fabacead53..5d0bc1be76 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_event.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_event.mdx @@ -16,11 +16,11 @@ The PPE pricing model offers a flexible monetization option for Actors on Apify 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 PPE pricing model](#example-of-a-ppe-pricing-model). +The details on how your cost is computed can be found in [Example of a PPE pricing](#example-of-a-ppe-pricing). :::tip Additional benefits -Actors that implement PPE pricing receive additional benefits, including increased visibility in Apify Store and enhanced discoverability for users looking for monetized solutions. +Actors that implement PPE pricing receive additional benefits, including increased visibility in Apify Store and enhanced discoverability. ::: @@ -132,44 +132,36 @@ When using [Crawlee](https://crawlee.dev/), use `crawler.autoscaledPool.abort()` ## Best practices for PPE Actors -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. +Use our [SDKs](/sdk) (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. SDKs help you 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 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": 512, - "maxMemoryMbytes": 1024, -} -``` +### Use synthetic start event `apify-actor-start` -:::note Memory requirements for browser-based scraping +:::info Synthetic Actor recommended -When using browser automation tools like Puppeteer or Playwright for web scraping, increase the memory limits to accommodate the browser's memory usage. +We recommend using the synthetic Actor start event in PPE Actors. It benefits both you and your users. ::: -### Use synthetic start event `apify-actor-start` - -This event is automatically charged by the Apify platform when an Actor is started or resurrected. +Starting an Actor takes time, and creates additional cost for the Actor creator, because the profit equals revenue minus platform costs. -Users of your Actor are charged one event for each GB of memory used by the Actor (at least one event per run). We _strongly_ suggest setting the price of this event to $0.0001 to remain competitive in the Store and attractive for your customers. If you define this event, you also save 5 seconds of Actor runtime from each Actor run, which won't be deducted from your payout profits. +One of the options to charge for the time spent on starting the Actor is to charge an “Actor start” event. Unfortunately, this makes your Actor comparably expensive with other tools on the market (outside of [Apify Store](/platform/console/store)) that do not incur this startup cost. -:::note Automatic charging of synthetic start event +We want to make it easier for Actor creators to stay competitive, but also help them to be profitable. Therefore, we have the Apify Actor synthetic start event `apify-actor-start`. This event is enabled by default for all new PPE Actors, and when you use it Apify will cover the compute unit cost of the first 5 seconds of every Actor run. -You must _not_ manually charge for the synthetic start event (`apify-actor-start`) in your Actor code. +The default price of the event is set intentionally low. This pricing means that the free 5 seconds of compute we provide costs us more than the revenue generated from the event. We've made this investment to _support our creator community_ by reducing your startup costs while keeping your Actors competitively priced for users. -If you attempt to charge this event yourself, the operation will fail. -This event is _always_ charged automatically by the Apify platform whenever your Actor starts or is resurrected. +#### How the synthetic start event works -::: +- The Apify Actor start event is _automatically enabled_ for all new PPE Actors. For existing Actors, you can enable it in Apify Console. +- Apify _automatically charges_ the event. + - You must _not_ manually charge for the synthetic start event (`apify-actor-start`) in your Actor code. If you attempt to charge this event yourself, the operation will fail. +- The default price of the event is _$0.00005_, which equals _$0.05 per 1,000 starts_. We recommend keeping the default price to keep your Actors competitive. +- The number of events charged _depends on the memory_ of the Actor run. Up to and including 1 GB of RAM, the event is charged once. Then it's charged once for each extra GB of memory. For example: + - 128 MB RAM: 1 event, $0.00005 + - 1 GB RAM: 1 event, $0.00005 + - 4 GB RAM: 4 events, $0.0002 +- You can increase the price of the event if you wish, but you _won't get more free compute_. +- You can delete the event if you wish, but if you do, you will _lose the free 5 seconds_ of compute. #### Synthetic start event for new Actors @@ -179,18 +171,40 @@ For new Actors, this event is added automatically as you can see on the followin #### Synthetic start event for existing Actors -If you have existing Actors, you can add this event manually in Apify Console. +If you have existing Actors, you can add this event manually in Apify Console in the **Publication** tab. #### Synthetic start event for Actors with start event Your Actor might already have a start event defined, such as `actor-start` or another variant of the event name. In this case, you can choose whether to use the synthetic start event or keep the existing start event. -If you want to use the synthetic start event, remove the existing start event from your Actor and add the synthetic start event in Apify Console. +If you want to use the synthetic start event, remove the existing start event from your Actor and add the synthetic start event in Apify Console in the **Publication** tab. + +### 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": 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 invalid input 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. +The snippet below shows how you can charge for invalid inputs using `Actor.pushData` when a dataset item is created and the `scraped-result` event is charged. + @@ -279,9 +293,9 @@ 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 +- _`post` event_: Each charge adds one social media post to the dataset +- _`profile` event_: Each charge adds one user profile to the dataset +- _`processed-image` event_: Each charge adds one processed image to the dataset - _`ai-analysis` event_: Each charge processes one document through an AI workflow (no tangible output, but valuable processing) :::note Additional context @@ -294,35 +308,97 @@ You can display a status message or push a record to the dataset to inform users 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 PPE pricing model +## Example of a PPE pricing -You make your Actor PPE and set the following pricing: +You create a social media monitoring Actor with 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 +- `post`: $0.002 per post - count every social media post you extract. +- `profile`: $0.005 per profile - count every user profile you extract. +- `sentiment-analysis`: $0.01 per post - count every post analyzed for sentiment, engagement metrics, and content classification using external LLM APIs. -During the first month, three users use your Actor: +:::info Fixed pricing vs. usage-based pricing -- _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 +You have two main strategies for charging AI-related operations: -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. +1. _Fixed event pricing_ (like `sentiment-analysis` above): Charge a fixed amount per operation, regardless of actual LLM costs +2. _Usage-based pricing_: Use events like `llm-token` that charge based on actual LLM usage costs -Your profit is computed only from the first two users, since they are on Apify paid plans. The revenue breakdown is: +Fixed pricing is simpler for users to predict, while usage-based pricing more accurately reflects your actual costs. + +::: -- _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 +### Pricing breakdown by user + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
UserPlanEventsChargesTotalPlatform cost
1Paid plan +
5,000 × post
+
1,000 × sentiment-analysis
+
+
5,000 × $0.002
+
1,000 × $0.01
+
$20$2.50
2Paid plan +
3,000 × post
+
500 × sentiment-analysis
+
+
3,000 × $0.002
+
500 × $0.01
+
$11$1.50
3Free plan +
1,000 × post
+
100 × sentiment-analysis
+
+
1,000 × $0.002
+
100 × $0.01
+
$3$0.40
+ +Your profit and costs are computed _only from the first two users_ since they are on Apify paid plans. + +The platform usage costs are just examples, but you can see the actual costs in the [Computing your costs for PPE and PPR Actors](/platform/actors/publishing/monetize/pricing-and-costs#computing-your-costs-for-ppe-and-ppr-actors) section. + +### Revenue breakdown + +- _Revenue (paid users only)_: $20 + $11 = _\$31_ +- _Platform cost (paid users only)_: $2.50 + $1.50 = _\$4_ +- _Profit_: 0.8 × $31 − $4 = _\$20.80_ ## Event names -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. +If you need to know your event names, 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 09ceea1331..6ab39b0420 100644 --- a/sources/platform/actors/publishing/monetize/pay_per_result.mdx +++ b/sources/platform/actors/publishing/monetize/pay_per_result.mdx @@ -16,12 +16,6 @@ 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 PPR pricing model](#example-of-a-ppr-pricing-model). -:::tip Additional benefits - -Actors that implement PPR pricing receive additional benefits, including increased visibility in Apify Store and enhanced discoverability for users looking for monetized solutions. - -::: - ## How is profit computed Your profit is calculated from the mentioned formula: @@ -35,6 +29,16 @@ where: 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. +## PPR vs PPE + +PPR charges based on the number of results produced. PPE lets you define pricing for individual events, and help you to make your pricing more flexible. You can charge for specific events directly from your Actor by calling the PPE charging API. + +:::info Learn more about PPE + +If you want to learn more about PPE, refer to the [Pay per event](/platform/actors/publishing/monetize/pay-per-event) section. + +::: + ## Best practices for PPR Actors To ensure profitability, check the following best practices. @@ -199,21 +203,72 @@ Example scenarios: This ensures that every run generates at least one result, guaranteeing that users are charged appropriately for using your Actor. -## Example of PPR pricing model - -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 -- _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 +## Example of PPR pricing + +You make your Actor PPR and set the price to be _$1/1,000 results_. During the first month, three users use your Actor. + +### Pricing breakdown by user + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
UserPlanResultsChargesTotalPlatform cost
1Paid plan +
50,000 results
+
+
50,000 ÷ 1,000 × $1.00
+
$50.00$5.00
2Paid plan +
20,000 results
+
+
20,000 ÷ 1,000 × $1.00
+
$20.00$2.00
3Free plan +
5,000 results
+
+
5,000 ÷ 1,000 × $1.00
+
$5.00$0.50
+ +Your profit and costs are computed _only from the first two users_ since they are on Apify paid plans. + +The platform usage costs are just examples, but you can see the actual costs in the [Computing your costs for PPE and PPR Actors](/platform/actors/publishing/monetize/pricing-and-costs#computing-your-costs-for-ppe-and-ppr-actors) section. + +### Revenue breakdown + +- _Revenue (paid users only): $50.00 + $20.00 = $70.00_ +- _Platform cost (paid users only): $5.00 + $2.00 = $7.00_ +- _Profit: 0.8 × $70.00 − $7.00 = $49.00_ ## Next steps diff --git a/sources/platform/actors/running/runs_and_builds.md b/sources/platform/actors/running/runs_and_builds.md index e6176b1197..9accc07dae 100644 --- a/sources/platform/actors/running/runs_and_builds.md +++ b/sources/platform/actors/running/runs_and_builds.md @@ -17,7 +17,7 @@ An Actor is a combination of source code and various settings in a Docker contai A Docker image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries, and settings. For more information visit Docker's [site](https://www.docker.com/resources/what-container/). ::: -With every new version of an Actor, a new build is created. Each Actor build has its number (for example, **1.2.34**), and some builds are tagged for easier use (for example, _latest_ or _beta_). When running an Actor, you can choose what build you want to run by selecting a tag or number in the run options. +With every new version of an Actor, a new build is created. Each Actor build has its number (for example, **1.2.34**), and some builds are tagged for easier use (for example, _latest_ or _beta_). When running an Actor, you can choose what build you want to run by selecting a tag or number in the run options. To change which build a tag refers to, you can reassign it using the [Actor update](/api/v2/act-put) API endpoint. ![Actor run options](./images/runs_and_builds/actor-run-options.png)