diff --git a/docs/02_concepts/08_access_apify_api.mdx b/docs/02_concepts/08_access_apify_api.mdx
index 774002bc..94868bd3 100644
--- a/docs/02_concepts/08_access_apify_api.mdx
+++ b/docs/02_concepts/08_access_apify_api.mdx
@@ -28,7 +28,7 @@ You select a resource with the matching method (for example, `Actor.apify_client
## Actor new client
-To create a completely new instance of the client (for example, to use a different user's token or change the client configuration), use the `Actor.new_client` method. It accepts an optional `token` and `api_url`, along with retry and timeout settings (`max_retries`, `min_delay_between_retries`, `timeout`), and returns a fresh `ApifyClientAsync`:
+To create a completely new instance of the client (for example, to use a different user's token or change the client configuration), use the `Actor.new_client` method. It accepts an optional `token`, `api_url`, and `api_public_url`, along with retry and timeout settings (`max_retries`, `min_delay_between_retries`, `timeout`), and returns a fresh `ApifyClientAsync`:
{ActorNewClientExample}
diff --git a/src/apify/_actor.py b/src/apify/_actor.py
index 9a1382d2..526146cf 100644
--- a/src/apify/_actor.py
+++ b/src/apify/_actor.py
@@ -597,6 +597,7 @@ def new_client(
*,
token: str | None = None,
api_url: str | None = None,
+ api_public_url: str | None = None,
max_retries: int | None = None,
min_delay_between_retries: timedelta | None = None,
timeout: timedelta | None = None,
@@ -604,15 +605,18 @@ def new_client(
"""Return a new instance of the Apify API client.
The `ApifyClientAsync` class is provided by the [apify-client](https://github.com/apify/apify-client-python)
- package, and it is automatically configured using the `APIFY_API_BASE_URL` and `APIFY_TOKEN` environment
- variables.
+ package, and it is automatically configured using the `APIFY_API_BASE_URL`, `APIFY_API_PUBLIC_BASE_URL` and
+ `APIFY_TOKEN` environment variables.
You can override the token via the available options. That's useful if you want to use the client
as a different Apify user than the SDK internals are using.
Args:
token: The Apify API token.
- api_url: The URL of the Apify API server to which to connect to. Defaults to https://api.apify.com.
+ api_url: The URL of the Apify API server to which to connect to. Defaults to the `APIFY_API_BASE_URL`
+ environment variable.
+ api_public_url: The globally accessible URL of the Apify API server, used to build public URLs of resources.
+ Defaults to the `APIFY_API_PUBLIC_BASE_URL` environment variable.
max_retries: How many times to retry a failed request at most.
min_delay_between_retries: How long will the client wait between retrying requests
(increases exponentially from this value).
@@ -626,6 +630,7 @@ def new_client(
client_kwargs: dict[str, Any] = {
'token': token or self.configuration.token,
'api_url': api_url or self.configuration.api_base_url,
+ 'api_public_url': api_public_url or self.configuration.api_public_base_url,
'compression': 'brotli',
}
if max_retries is not None:
diff --git a/tests/unit/actor/test_actor_helpers.py b/tests/unit/actor/test_actor_helpers.py
index e8b0d8f9..267c412d 100644
--- a/tests/unit/actor/test_actor_helpers.py
+++ b/tests/unit/actor/test_actor_helpers.py
@@ -12,6 +12,7 @@
from apify_client import ApifyClientAsync
from apify_client._models import Run
+from apify_client._resource_clients import KeyValueStoreClientAsync
from crawlee.events._types import Event
from apify import Actor, Webhook
@@ -85,6 +86,25 @@ async def test_new_client_config_creation(monkeypatch: pytest.MonkeyPatch) -> No
await my_actor.exit()
+async def test_new_client_uses_configured_api_public_base_url(monkeypatch: pytest.MonkeyPatch) -> None:
+ """`new_client` builds public URLs on the configured `api_public_base_url` host."""
+ monkeypatch.setenv(ApifyEnvVars.API_BASE_URL, 'http://internal-api.example.com')
+ monkeypatch.setenv(ApifyEnvVars.API_PUBLIC_BASE_URL, 'https://public-api.example.com')
+ monkeypatch.setattr(KeyValueStoreClientAsync, 'get', AsyncMock(return_value=None))
+ my_actor = _ActorType()
+ await my_actor.init()
+
+ client = my_actor.new_client()
+ public_url = await client.key_value_store('store-id').get_record_public_url('key')
+ assert public_url == 'https://public-api.example.com/v2/key-value-stores/store-id/records/key'
+
+ client_with_override = my_actor.new_client(api_public_url='https://override.example.com')
+ public_url = await client_with_override.key_value_store('store-id').get_record_public_url('key')
+ assert public_url == 'https://override.example.com/v2/key-value-stores/store-id/records/key'
+
+ await my_actor.exit()
+
+
async def test_call_actor(apify_client_async_patcher: ApifyClientAsyncPatcher, fake_actor_run: Run) -> None:
apify_client_async_patcher.patch('actor', 'call', return_value=fake_actor_run)
actor_id = 'some-actor-id'