Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99
Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 832
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839 tag:devcenter.heroku.com,2005:/articles/feedHeroku Dev Center ArticlesHeroku2025-10-13T21:08:53Ztag:devcenter.heroku.com,2005:Article/170762025-10-13T21:08:53Z2025-10-13T21:08:53ZOpenAI Compatibility for Chat Completions<p>Heroku’s <a href="https://devcenter.heroku.com/articles/heroku-inference-api">Managed Inference and Agents Add-on API</a> offers broad <a href="http://openai.com/">OpenAI</a> compatibility that works for most use cases. You can use familiar OpenAI SDK patterns while gaining access to Heroku’s infrastructure, security, and specialized tools.</p>
<h2 id="get-started-with-the-openai-sdk">Get Started With the OpenAI SDK</h2>
<h3 id="prerequisites">Prerequisites</h3>
<p>To use the OpenAI SDK with Heroku, you need:</p>
<ul>
<li>The <a href="https://devcenter.heroku.com/articles/heroku-inference">Heroku Managed Inference and Agents add-on</a></li>
<li>An <a href="https://platform.openai.com/docs/libraries">official OpenAI SDK</a></li>
</ul>
<p>We recommend always using the latest version of the OpenAI SDK.</p>
<h3 id="set-up-a-heroku-app-to-use-the-openai-sdk">Set Up a Heroku App to Use the OpenAI SDK</h3>
<p>When you attach a model resource to your app using <code>heroku ai:models:create</code>, the add-on automatically adds some config vars to your app’s environment.</p>
<p>Include your add-on’s config vars in your code:</p>
<ol>
<li>Set the base URL to the <code>INFERENCE_URL</code> for your add-on.</li>
<li>Set the API key to the <code>INFERENCE_KEY</code> for your add-on.</li>
<li>Set the model in the request to the <code>INFERENCE_MODEL_ID</code>.</li>
</ol>
<h4 id="example-setup-for-python-openai-sdk">Example Setup for Python OpenAI SDK</h4>
<pre class="language-python"><code class="language-python">from openai import OpenAI
import os
api_key=os.getenv("INFERENCE_KEY")
api_url=os.getenv("INFERENCE_URL")
model=os.getenv("INFERENCE_MODEL_ID")
client = OpenAI(
api_key=api_key, # Your Managed Inference API key
base_url=api_url + "/v1/" # Managed Inference API endpoint, for example, https://us.inference.heroku.com
)
response = client.chat.completions.create(
model=model, # Add-on plan name
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What should I build today?"}
],
)
print(response.choices[0].message.content)
</code></pre>
<h2 id="request-parameter-support">Request Parameter Support</h2>
<h3 id="request-fields">Request Fields</h3>
<table><thead>
<tr>
<th>Request Field</th>
<th>Supported?</th>
</tr>
</thead><tbody>
<tr>
<td>model</td>
<td>Yes, use add-on plan name</td>
</tr>
<tr>
<td>messages</td>
<td>Yes</td>
</tr>
<tr>
<td>modalities</td>
<td>Yes, for type <code>text</code></td>
</tr>
<tr>
<td>logprobs</td>
<td>Yes</td>
</tr>
<tr>
<td>max_completion_tokens</td>
<td>Yes</td>
</tr>
<tr>
<td>parallel_tool_calls</td>
<td>Yes for Anthropic and OpenAI models, ignored for nova models</td>
</tr>
<tr>
<td>reasoning_effort</td>
<td>Yes</td>
</tr>
<tr>
<td>stop</td>
<td>Yes</td>
</tr>
<tr>
<td>stream</td>
<td>Yes</td>
</tr>
<tr>
<td>stream_options</td>
<td>Yes</td>
</tr>
<tr>
<td>temperature</td>
<td>Yes</td>
</tr>
<tr>
<td>tool_choice</td>
<td><a href="#tool-choice">Yes*</a></td>
</tr>
<tr>
<td>tool_options</td>
<td>Yes</td>
</tr>
<tr>
<td>tools</td>
<td>Yes</td>
</tr>
<tr>
<td>top_p</td>
<td>Yes</td>
</tr>
<tr>
<td>n</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>frequency_penalty</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>logprobs</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>audio</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>logit_bias</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>store</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>metadata</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>prediction</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>presence_quality</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>prompt_cache_key</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>response_format</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>safety_identifier</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>service_tier</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>store</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>top_logprobs</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>verbosity</td>
<td>Yes, but ignored</td>
</tr>
<tr>
<td>web_search_options</td>
<td>Yes, but ignored</td>
</tr>
</tbody></table>
<h3 id="request-messages">Request Messages</h3>
<table><thead>
<tr>
<th>Message Type</th>
<th>Supported?</th>
</tr>
</thead><tbody>
<tr>
<td>Developer</td>
<td>Yes</td>
</tr>
<tr>
<td>System</td>
<td>Yes</td>
</tr>
<tr>
<td>User</td>
<td>Yes, except for audio and file content types</td>
</tr>
<tr>
<td>Assistant</td>
<td>Yes, except for audio content type</td>
</tr>
<tr>
<td>Tool</td>
<td>Yes</td>
</tr>
</tbody></table>
<h3 id="tool-choice">Tool Choice</h3>
<p>The <code>tool_choice</code> parameter is supported, except for <a href="https://platform.openai.com/docs/guides/function-calling#custom-tools">custom tool</a> choice.</p>
<div class="note">
<p>To learn more about using <code>tool_choice</code>, see the <a href="https://platform.openai.com/docs/api-reference/chat/create#chat_create-tool_choice">OpenAI docs</a>.</p>
</div>
<h3 id="tools">Tools</h3>
<p>Function type tools are supported. Custom tools are unsupported.</p>
<div class="note">
<p>To learn more about using tools, see the <a href="https://platform.openai.com/docs/api-reference/chat/create#chat_create-tools">OpenAI docs</a>.</p>
</div>
<h2 id="response-parameter-support">Response Parameter Support</h2>
<h3 id="response-fields">Response Fields</h3>
<table><thead>
<tr>
<th>Response Field</th>
<th>Supported?</th>
</tr>
</thead><tbody>
<tr>
<td>choices</td>
<td>Yes</td>
</tr>
<tr>
<td>created</td>
<td>Yes</td>
</tr>
<tr>
<td>id</td>
<td>Yes</td>
</tr>
<tr>
<td>model</td>
<td>Yes</td>
</tr>
<tr>
<td>object</td>
<td>Yes</td>
</tr>
<tr>
<td>service_tier</td>
<td>No</td>
</tr>
<tr>
<td>system_fingerprint</td>
<td>Yes</td>
</tr>
<tr>
<td>usage</td>
<td>Yes</td>
</tr>
</tbody></table>
<h3 id="choice-fields">Choice Fields</h3>
<table><thead>
<tr>
<th>Choice Field</th>
<th>Supported?</th>
</tr>
</thead><tbody>
<tr>
<td>index</td>
<td>Yes</td>
</tr>
<tr>
<td>message</td>
<td>Yes, except for annotations and audio</td>
</tr>
<tr>
<td>logprobs</td>
<td>Yes</td>
</tr>
<tr>
<td>finish_reason</td>
<td>Yes</td>
</tr>
</tbody></table>
<h3 id="usage-fields">Usage Fields</h3>
<table><thead>
<tr>
<th>Usage Field</th>
<th>Supported?</th>
</tr>
</thead><tbody>
<tr>
<td>prompt_tokens</td>
<td>Yes</td>
</tr>
<tr>
<td>completion_tokens</td>
<td>Yes, except for annotations and audio</td>
</tr>
<tr>
<td>total_tokens</td>
<td>Yes</td>
</tr>
</tbody></table>
<p>Other usage field types are unsupported.</p>
<h2 id="limitations">Limitations</h2>
<h3 id="extended-thinking">Extended Thinking</h3>
<p><a href="https://devcenter.heroku.com/articles/heroku-inference-api-model-claude-3-7-sonnet">Claude 3.7 Sonnet</a> and <a href="https://devcenter.heroku.com/articles/heroku-inference-api-model-claude-4-sonnet">Claude 4 Sonnet</a> support extended thinking. You can use the extensive <code>extended_reasoning</code> parameter we expose, or OpenAI’s <code>reasoning_effort</code> parameter (low, medium, high mapping to fixed reasoning budget tokens).</p>
<div class="note">
<p>If you use the OpenAI client, you don’t see reasoning blocks in the response. Set <code>include_reasoning</code> to false.</p>
</div>
<h4 id="python-extended-thinking-example">Python Extended Thinking Example</h4>
<pre class="language-python"><code class="language-python">response = client.chat.completions.create(
model=model, # Must be Claude Sonnet 3.7 or 4
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Who are you?"}
],
extra_body={
"extended_thinking": {
"enabled": True,
"budget_tokens": 2000,
"include_reasoning": False
}
}
)
</code></pre>
<h3 id="allowing-ignored-parameters">Allowing Ignored Parameters</h3>
<p>The Managed Inference and Agents Add-on API returns an error for unrecognized parameters. To disable this error, set <code>allow_ignored_params</code> to true. Ignoring parameters is useful if you’re using an older version of the SDK with parameters that aren’t fully supported by Heroku.</p>
<h3 id="python-allowing-ignored-parameters-example">Python Allowing Ignored Parameters Example</h3>
<pre class="language-python"><code class="language-python">response = client.chat.completions.create(
model=model, # Must be Claude Sonnet 3.7 or 4
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Who are you?"}
],
extra_body={
"allow_ignored_params": True
}
)
</code></pre>
<h3 id="limitations-for-tool-calling">Limitations for Tool Calling</h3>
<p>The <code>content</code> field must be populated to use tool calling. If <code>content</code> is empty, the API throws a validation error. To prevent empty tool responses, you can either ensure the tool always has a response or populate empty <code>content</code> fields with default values in your application code.</p>
<h2 id="additional-reading">Additional Reading</h2>
<ul>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference-api">Heroku Managed Inference and Agents Add-on API</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference-api-model-cards">Managed Inference and Agents API Model Cards</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference-tools">Using Heroku Tools with the Managed Inference and Agents Add-on</a>
*<a href="https://devcenter.heroku.com/categories/inference-quick-start-guides">Heroku Inference Quick Start Guides</a></li>
</ul>tag:devcenter.heroku.com,2005:Article/91192025-10-13T16:05:59Z2025-10-13T16:05:59ZExpress Nodes Dedicated IP<p><a href="https://elements.heroku.com/addons/dedicatedip">Express Nodes Dedicated IP</a> is an add-on that empowers your Heroku applications with two static, dedicated IP addresses for outbound traffic. With both IPs equal in quality and performance, you have the flexibility to balance your requests or use one as a fallback.</p>
<p>Whether you choose the Test plan with 10GB of bandwidth and shared static IPs, or the Unlimited plan with unlimited bandwidth and fully dedicated static IPs, your app always benefits from high-quality, fresh, and cooled-down IPs. In addition, the IPs supports HTTP and SOCKSv5 protocols, making it compatible with virtually any language or framework.</p>
<h2 id="key-features">Key Features</h2>
<ol>
<li>Two IPs per plan: Ensure redundancy and failover.</li>
<li>High-quality IPs: Corporate level IPs - Fresh, cooled-down IPs.</li>
<li>Protocol support: HTTP and SOCKS5.</li>
</ol>
<h2 id="provisioning-the-add-on">Provisioning the Add-on</h2>
<p>To get started, add Express Nodes Dedicated IP to your Heroku application using the CLI.</p>
<p>For the Unlimited plan (2 dedicated static IPs, unlimited bandwidth), run:</p>
<pre class="language-term"><code class="language-term">heroku addons:create dedicatedip:unlimited --app your-app-name
</code></pre>
<p>For the Test plan (2 shared static IPs, 10GB bandwidth), run:</p>
<pre class="language-term"><code class="language-term">heroku addons:create dedicatedip:test --app your-app-name
</code></pre>
<p>After successful provisioning, this message displays:</p>
<pre class="language-term"><code class="language-term">IPs Provisioned Successfully
Created dedicatedip as DEDICATED_IP_HTTP_PROXY_1, DEDICATED_IP_HTTP_PROXY_2, DEDICATED_IP_SOCKS_PROXY_1, DEDICATED_IP_SOCKS_PROXY_2
</code></pre>
<p>After installing the add-on, the application is fully integrated with the add-on.</p>
<h2 id="view-assigned-ips">View Assigned IPs</h2>
<p>Run this command to view the details of IPs provisioned to your app:</p>
<pre class="language-term"><code class="language-term">heroku config --app your-app-name
</code></pre>
<h2 id="test-your-ip-connection">Test Your IP Connection</h2>
<p>Run the following command to open an interactive bash session for your Heroku app</p>
<pre class="language-term"><code class="language-term">heroku run bash --app your-app-name
</code></pre>
<p>Within the bash session, run the following command to test the connection:</p>
<pre class="language-term"><code class="language-term">curl -x "$DEDICATED_IP_HTTP_PROXY_1" https://ipinfo.io
</code></pre>
<h2 id="dashboard-overview">Dashboard Overview</h2>
<p>We provide an easy to use dashboard so you can mange your services and IPs. Here’s how you can log into the dashboard:</p>
<pre class="language-term"><code class="language-term">heroku addons:open dedicatedip --app your-app-name
</code></pre>
<p>We use Heroku’s SSO which automatically logs you into our dashboard.</p>
<h2 id="local-setup">Local Setup</h2>
<p>To ensure your development environment accurately mirrors production, replicate the Express Nodes Dedicated IP configuration locally. Environment parity enables you to test your app against our proxy service without needing to deploy every change.</p>
<h3 id="environment-setup">Environment Setup</h3>
<p>Express Nodes Dedicated IP adds several config variables to your Heroku app, as noted in the message shown after provisioning. These variables include:</p>
<ul>
<li><code>DEDICATED_IP_HTTP_PROXY_1</code></li>
<li><code>DEDICATED_IP_SOCKS_PROXY_1</code></li>
<li><code>DEDICATED_IP_HTTP_PROXY_2</code></li>
<li><code>DEDICATED_IP_SOCKS_PROXY_2</code></li>
</ul>
<p>You can use the <a href="https://devcenter.heroku.com/articles/heroku-local">Heroku Local</a> command-line tool to set up your development environment. Heroku Local reads configuration variables from a <code>.env</code> file, so you should replicate the necessary variables locally. Run the following commands to append each variable to your <code>.env</code> file:</p>
<pre class="language-term"><code class="language-term">heroku config:get --app your-app-name DEDICATED_IP_HTTP_PROXY_1 -s >> .env
heroku config:get --app your-app-name DEDICATED_IP_SOCKS_PROXY_1 -s >> .env
heroku config:get --app your-app-name DEDICATED_IP_HTTP_PROXY_2 -s >> .env
heroku config:get --app your-app-name DEDICATED_IP_SOCKS_PROXY_2 -s >> .env
</code></pre>
<div class="note">
<p>Never commit credentials and other sensitive configuration values to source control. To prevent accidental commits, add the <code>.env</code> file to your <code>.gitignore</code> file:</p>
</div>
<pre class="language-term"><code class="language-term">echo .env >> .gitignore
</code></pre>
<h2 id="use-with-ruby">Use With Ruby</h2>
<p>Here’s a simple example using Ruby’s built-in Net::HTTP library, no additional gems required. This snippet demonstrates how to route your outbound requests via Express Nodes Dedicated IP using the HTTP proxy.</p>
<pre class="language-ruby"><code class="language-ruby">#!/usr/bin/env ruby
require 'net/http'
require 'uri'
# Parse the proxy URL from the environment variable.
proxy_uri = URI.parse(ENV['DEDICATED_IP_HTTP_PROXY_1'])
# Create an HTTP object that uses the proxy.
http = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
# Specify the target URL.
uri = URI.parse('http://ipinfo.io/')
begin
puts "Connecting through proxy: #{proxy_uri.host}:#{proxy_uri.port}..."
# Send the GET request via the proxy.
response = http.get_response(uri)
if response.is_a?(Net::HTTPSuccess)
puts "Connection successful!"
puts "Your IP is: #{response.body.strip}"
else
puts "Error: HTTP #{response.code} - #{response.message}"
end
rescue => e
puts "Error occurred: #{e.class} - #{e.message}"
end
</code></pre>
<p>Set the appropriate environment variable, <code>DEDICATED_IP_HTTP_PROXY_1</code>, in your Heroku app configuration or local environment, and you’re ready to go. This minimal setup ensures that your Ruby application can reliably route its requests through our static IPs without any extra dependencies.</p>
<h2 id="use-with-python">Use with Python</h2>
<p>Express Nodes Dedicated IP works seamlessly with Python’s popular HTTP libraries. Here are a few examples to help you get started without any extra dependencies.</p>
<h3 id="using-the-requests-library">Using the Requests Library</h3>
<p>You can specify the proxy URLs directly using a proxy dictionary:</p>
<pre class="language-python"><code class="language-python">import os
import requests
# Create a proxy dictionary using the environment variables.
proxies = {
"http": os.getenv('DEDICATED_IP_HTTP_PROXY_1')
}
# Make a request through the proxy.
response = requests.get("http://ipinfo.io/ip", proxies=proxies)
print("Your IP is:", response.text.strip())
</code></pre>
<p>Alternatively, set the proxy globally so all requests automatically use it:</p>
<pre class="language-python"><code class="language-python">import os
import requests
# Set global proxy environment variables.
os.environ['http_proxy'] = os.getenv('DEDICATED_IP_HTTP_PROXY_1')
# Any subsequent requests use the defined proxies.
response = requests.get("http://ipinfo.io/ip")
print("Your IP is:", response.text.strip())
</code></pre>
<h2 id="use-with-php">Use with PHP</h2>
<p>Express Nodes Dedicated IP integrates with PHP using cURL. Here are examples for both HTTP and SOCKS5 proxies.</p>
<h3 id="http-proxy-with-php-curl">HTTP Proxy with PHP cURL</h3>
<p>Use the following PHP code to send a request via our HTTP proxy:</p>
<pre class="language-php"><code class="language-php"><?php
function proxyRequest() {
// Get the HTTP proxy URL from the environment variable.
$proxy = getenv("DEDICATED_IP_HTTP_PROXY_1");
// Initialize cURL with the target URL.
$ch = curl_init("https://ipinfo.io/ip");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Set the proxy for the cURL request.
curl_setopt($ch, CURLOPT_PROXY, $proxy);
// Execute the request.
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
$response = proxyRequest();
print($response);
?>
</code></pre>
<h3 id="socks5-proxy-with-php-curl">SOCKS5 Proxy with PHP cURL</h3>
<p>Use the following PHP code to send a request via our SOCKS5 proxy:</p>
<pre class="language-php"><code class="language-php"><?php
function proxyRequest() {
// Get the SOCKS5 proxy URL from the environment variable.
$proxy = getenv("DEDICATED_IP_SOCKS_PROXY_1");
// Initialize cURL with the target URL.
$ch = curl_init("https://ipinfo.io/ip");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Set the proxy for the cURL request.
curl_setopt($ch, CURLOPT_PROXY, $proxy);
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
// Execute the request.
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
$response = proxyRequest();
print($response);
?>
</code></pre>
<h2 id="migrating-between-plans">Migrating Between Plans</h2>
<p>You can upgrade or downgrade your Express Nodes Dedicated IP plan by passing the plan name with the Heroku CLI. For example:</p>
<p>To upgrade to the Unlimited plan:</p>
<div class="note">
<p>If you upgrade your plan from Test to other plans, you get new dedicated IPs as the Test plan has shared IPs. Your IPs remain unchanged when migrating between paid plans.</p>
</div>
<pre class="language-term"><code class="language-term">heroku addons:upgrade dedicatedip:unlimited --app your-app-name
</code></pre>
<p>To downgrade to Test plan:</p>
<div class="note">
<p>If you downgrade from a paid plan to the Test plan, you lose your dedicated IPs and your app gets assigned shared IPs. The Test plan is only meant for testing the add-on.</p>
</div>
<pre class="language-term"><code class="language-term">heroku addons:upgrade dedicatedip:test --app your-app-name
</code></pre>
<div class="callout">
<p>You can only subscribe to the Test plan once per application to avoid any abuse of our service.</p>
</div>
<h2 id="removing-the-add-on">Removing The Add-on</h2>
<p>Run this command to remove the add-on.</p>
<div class="warning">
<p>When you remove the add-on, the IPs provisioned to your app terminate, which can affect your application if you configured proxies for use in scripts or outbound requests.</p>
</div>
<pre class="language-term"><code class="language-term">heroku addons:destroy dedicatedip --app your-app-name
</code></pre>
<h2 id="faqs">FAQs</h2>
<h3 id="can-i-access-external-databases-like-mysql-or-postgres">Can I access external databases like MySQL or Postgres?</h3>
<p>Yes, you can connect to external databases using the proxy.</p>
<h3 id="can-i-allowlist-my-ip-elsewhere">Can I allowlist my IP elsewhere?</h3>
<p>Absolutely, if you’re on a paid plan. Since paid plans have static IPs dedicated to you, it’s perfect for firewall allowlisting, database access, API restrictions, and more. It’s ideal to allowlist both IPs simultaneously so if there’s a need to change one IP, you’re not locked out. It’s not recommended to allowlist IPs if you’re on the Test plan.</p>
<h2 id="support">Support</h2>
<p>You’re covered with premium support. If you have any issues related to the service, or if you want to understand more about the IPs and services, Express Nodes’ award-winning support team is always there to help. Reach out to <a href="mailto:hello@expressnodes.com">hello@expressnodes.com</a>.</p>tag:devcenter.heroku.com,2005:Article/114322025-10-01T13:24:18Z2025-10-01T13:24:18ZPure Memcache<p><a href="https://elements.heroku.com/addons/pure-memcache">Pure Memcache</a> is an add-on for adding Memcached servers to your Heroku application. The built-in functionality offers fault-tolerant caching by spreading the load across different server instances and availability zones.</p>
<h2 id="provisioning-the-add-on">Provisioning the Add-on</h2>
<p>Pure Memcache offers several plans with different cache sizes. The Value tier is the most cost-effective, while the Performance tier offers faster speed.</p>
<p>Attach Pure Memcache to a Heroku application via the CLI:</p>
<div class="callout">
<p>Reference the <a href="https://elements.heroku.com/addons/pure-memcache">Pure Memcache Elements Page</a> for a list of available plans and regions.</p>
</div>
<pre class="language-term"><code class="language-term">$ heroku addons:create pure-memcache:value1
Creating pure-memcache on example-app... free
Your add-on has been provisioned successfully
</code></pre>
<p>After provisioning Pure Memcache, the following config vars are available in the attached app’s configuration:</p>
<ul>
<li><code>PURE_MEMCACHE_SERVERS</code></li>
<li><code>PURE_MEMCACHE_USERNAME</code></li>
<li><code>PURE_MEMCACHE_PASSWORD</code></li>
</ul>
<p>You can see the config var via the <code>heroku config:get</code> command:</p>
<pre class="language-term"><code class="language-term">$ heroku config:get PURE_MEMCACHE_SERVERS
</code></pre>
<p>After installing Pure Memcache, the application is fully configured to integrate with the add-on.</p>
<div class="warning">
<p>The Pure Memcache servers aren’t set up to use encryption, as it slows the caching. We recommend not using Pure Memcache for confidential data.</p>
</div>
<h2 id="using-pure-memcache-from-ruby-and-rails">Using Pure Memcache from Ruby and Rails</h2>
<p>Use the <a href="https://github.com/mperham/dalli">Dalli</a> gem to connect to Pure Memcache:</p>
<p>In your <code>Gemfile</code> add:</p>
<pre class="language-ruby"><code class="language-ruby">gem 'dalli'
</code></pre>
<p>Then run:</p>
<pre class="language-term"><code class="language-term">$ bundle install
</code></pre>
<p>You can then access Memcache with:</p>
<pre class="language-ruby"><code class="language-ruby">require 'dalli'
cache = Dalli::Client.new(ENV['PURE_MEMCACHE_SERVERS'].split(','),
{username: ENV['PURE_MEMCACHE_USERNAME'], password: ENV['PURE_MEMCACHE_PASSWORD']})
</code></pre>
<h3 id="rails">Rails</h3>
<p>After installing the Dalli gem, you can edit the <code>config/environments/production.rb</code> file to use Pure Memcache as your default Rails cache:</p>
<pre class="language-ruby"><code class="language-ruby">config.cache_store = :mem_cache_store, ENV['PURE_MEMCACHE_SERVERS'].split(','),
{username: ENV['PURE_MEMCACHE_USERNAME'], password: ENV['PURE_MEMCACHE_PASSWORD']}
</code></pre>
<h2 id="using-pure-memcache-from-node-js">Using Pure Memcache from Node.js</h2>
<p>Use the <code>memjs</code> package to access Pure Memcache from Node.js:</p>
<pre class="language-term"><code class="language-term">$ npm install memjs
</code></pre>
<p>Then you can create a client:</p>
<pre class="language-javascript"><code class="language-javascript">const memjs = require('memjs'); // or import memjs from 'memjs' if using ES modules
const client = memjs.Client.create(process.env.PURE_MEMCACHE_SERVERS, {
username: process.env.PURE_MEMCACHE_USERNAME,
password: process.env.PURE_MEMCACHE_PASSWORD,
failover: true
});
</code></pre>
<h2 id="using-pure-memcache-from-python">Using Pure Memcache from Python</h2>
<p>Use the <code>bmemcached</code> module to access Pure Memcache from Python.</p>
<p>First, install the module:</p>
<pre class="language-term"><code class="language-term">$ pip install python-binary-memcached
</code></pre>
<p>Then the you can create a client:</p>
<pre class="language-python"><code class="language-python">import os
import bmemcached
client = bmemcached.Client(os.environ.get('PURE_MEMCACHE_SERVERS').split(','), os.environ.get('PURE_MEMCACHE_USERNAME'), os.environ.get('PURE_MEMCACHE_PASSWORD'))
</code></pre>
<h2 id="using-pure-memcache-from-java">Using Pure Memcache from Java</h2>
<p>Use the <code>XMemcached</code> client to access Pure Memcache from Java.</p>
<p>First, add the XMemcached library to your Project Object Model file or <code>pom.xml</code>:</p>
<pre><code><dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.8</version>
</dependency>
</code></pre>
<p>Then you can create a XMemcached client:</p>
<pre class="language-java"><code class="language-java">List<InetSocketAddress> servers = AddrUtil.getAddresses(System.getenv("PURE_MEMCACHE_SERVERS").replace(",", " "));
AuthInfo authInfo = AuthInfo.plain(System.getenv("PURE_MEMCACHE_USERNAME"), System.getenv("PURE_MEMCACHE_PASSWORD"));
MemcachedClientBuilder builder = new XMemcachedClientBuilder(servers);
for (InetSocketAddress server : servers) builder.addAuthInfo(server, authInfo);
// Must use binary protocol
builder.setCommandFactory(new BinaryCommandFactory());
MemcachedClient client=builder.build();
</code></pre>
<h2 id="using-pure-memcache-from-php">Using Pure Memcache from PHP</h2>
<p>Use the <a href="http://www.php.net/manual/en/book.memcached.php">PHP Memcached Client</a> to connect from PHP.</p>
<p>First, add the following to your <code>composer.json</code> file:</p>
<pre><code>"require": {
"ext-memcached": "*"
}
</code></pre>
<p>Then run:</p>
<pre class="language-term"><code class="language-term">$ composer update
</code></pre>
<p>Then you can create a Memcached client:</p>
<pre class="language-php"><code class="language-php">$client = new Memcached();
$client->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
// use consistent hashing to allow adding or removing of servers without losing cached values
$client->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$client->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
// failover
$client->setOption(Memcached::OPT_REMOVE_FAILED_SERVERS, true);
// this should only be called once to avoid adding the servers multiple times...
$client->addServers(array_map(fn($server) => explode(':', $server, 2), explode(',', $_ENV['PURE_MEMCACHE_SERVERS'])));
$client->setSaslAuthData($_ENV['PURE_MEMCACHE_USERNAME'], $_ENV['PURE_MEMCACHE_PASSWORD']);
</code></pre>
<h2 id="migrating-between-plans">Migrating Between Plans</h2>
<div class="note">
<p>Application owners must carefully manage the migration timing to ensure proper application function during the migration process.</p>
</div>
<p>You can only upgrade and downgrade plans within the same tier as the Value and Performance tiers are implemented on completely different servers. To minimize the impact of upgrades and downgrades within a tier on your production environment, we recommend changing to the next nearest plan in size. By changing plans gradually over time, you can ensure the impact on your live service is minimal.</p>
<p>Use the <code>heroku addons:upgrade</code> command to migrate to a new plan.</p>
<pre class="language-term"><code class="language-term">$ heroku addons:upgrade pure-memcache:value2
-----> Upgrading pure-memcache:value 2 to example-app.. done, v18 ($49/mo)
Your plan has been updated to: pure-memcache:value 2
</code></pre>
<h2 id="removing-the-add-on">Removing the Add-on</h2>
<p>Remove Pure Memcache via the CLI:</p>
<div class="warning">
<p>This action destroys all associated data and you can’t undo it!</p>
</div>
<pre class="language-term"><code class="language-term">$ heroku addons:destroy pure-memcache
-----> Removing pure-memcache from example-app... done
</code></pre>
<h2 id="support">Support</h2>
<p>Submit all Pure Memcache support and runtime issues via one of the <a href="https://devcenter.heroku.com/articles/support-channels">Heroku Support channels</a>. Any non-support-related issues or product feedback is welcome at feedback@pureserv.link.</p>tag:devcenter.heroku.com,2005:Article/113952025-09-17T16:38:01Z2025-09-17T16:38:01ZHeroku CLI Interactive Prompt<p>The interactive prompt helps you run Heroku CLI commands by guiding you through the required inputs.</p>
<p>Prompting is particularly useful when you’re unsure about what required or optional arguments and flags a command uses.</p>
<h2 id="benefits">Benefits</h2>
<ul>
<li>Learn requirements for any command, like setting configuration vars</li>
<li>Run commands with multiple required flags easily, such as when creating new resources</li>
<li>Never forget optional arguments or flags when you run a command</li>
<li>Get descriptions for each input</li>
<li>Validate input before executing the command</li>
</ul>
<h2 id="usage">Usage</h2>
<p>Start prompting by adding <code>--prompt</code> after any command:
<code>term
$ heroku COMMAND --prompt
</code></p>
<h2 id="example-session">Example Session</h2>
<pre class="language-term"><code class="language-term">$ heroku config:set --prompt
Enter key: DATABASE_URL
Enter value: postgres://...
Setting DATABASE_URL and restarting example-app... done
</code></pre>
<h2 id="additional-reading">Additional Reading</h2>
<ul>
<li><a href="https://devcenter.heroku.com/articles/heroku-cli">Heroku CLI</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-cli-commands">Heroku CLI Commands</a></li>
<li><a href="https://devcenter.heroku.com/articles/cli-repl">Heroku CLI REPL</a></li>
<li>See code: <a href="https://github.com/heroku/cli/blob/v10.9.0/packages/cli/src/commands/prompt.ts">src/commands/prompt.ts</a>_</li>
</ul>tag:devcenter.heroku.com,2005:Article/113962025-09-17T16:37:16Z2025-09-17T16:37:16ZHeroku CLI REPL<p>The Heroku CLI REPL (Read-Eval-Print Loop) feature provides an interactive environment to run Heroku CLI commands without typing <code>heroku</code> each time.</p>
<p>Use it when running multiple commands in sequence or exploring the CLI.</p>
<h2 id="benefits">Benefits</h2>
<ul>
<li>Run commands without typing <code>heroku</code> each time</li>
<li><a href="#set-persistent-flags">Set and persist flags</a> across multiple commands</li>
<li>Get <a href="#command-completion">command completions</a> and help</li>
<li>See an interactive <a href="#command-history">command history</a></li>
<li>Persist session state</li>
</ul>
<h2 id="start-a-repl">Start a REPL</h2>
<p>Start a REPL interactive environment with this command:
<code>term
$ heroku --repl
</code></p>
<h2 id="exit-a-repl">Exit a REPL</h2>
<p>To exit the REPL, type <code>exit</code> or press <code>Ctrl</code>+<code>D</code>.</p>
<h2 id="set-persistent-flags">Set Persistent Flags</h2>
<p>You can set flags that persist across commands. For example, to persist an app’s name in your commands:</p>
<pre class="language-term"><code class="language-term">$ heroku --repl
heroku> set app example-app
setting --app to example-app
example-app> ps
=== example-app Dynos
web.1: up 2024/03/19 10:00:00 +0000 (~ 1h ago)
</code></pre>
<p>To view your persisted flags:</p>
<pre class="language-term"><code class="language-term">example-app> set
Flag Value
app example-app
</code></pre>
<p>To remove a persisted flag:</p>
<pre class="language-term"><code class="language-term">example-app> unset app
unsetting --app
heroku>
</code></pre>
<h2 id="command-completion">Command Completion</h2>
<p>The REPL provides intelligent command completion. Press <code>tab</code> to see available commands and options:</p>
<pre class="language-term"><code class="language-term">heroku> pipelines:create --app <tab><tab>
heroku> spaces:create --team <tab><tab>
</code></pre>
<p>The REPL supports completion for various resources including:</p>
<ul>
<li>Apps</li>
<li>Organizations</li>
<li>Teams</li>
<li>Spaces</li>
<li>Pipelines</li>
<li>Add-ons</li>
<li>Domains</li>
<li>Dynos</li>
<li>Releases</li>
<li>Stacks</li>
</ul>
<h2 id="command-history">Command History</h2>
<p>The REPL maintains a history of your commands. View your history with:</p>
<pre class="language-term"><code class="language-term">heroku> history
</code></pre>
<p>Use the up and down arrow keys to navigate through your command history.</p>
<h2 id="additional-reading">Additional Reading</h2>
<ul>
<li><a href="https://devcenter.heroku.com/articles/heroku-cli">Heroku CLI</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-cli-commands">Heroku CLI Commands</a></li>
<li><a href="https://devcenter.heroku.com/articles/cli-prompt">Heroku CLI Interactive Prompt</a></li>
</ul>tag:devcenter.heroku.com,2005:Article/170852025-09-17T16:34:52Z2025-09-17T16:35:41ZHeroku App Lifecycle<p>Heroku is a cloud platform that allows developers to deploy, manage, and scale applications effortlessly. It abstracts away much of the complexity involved in infrastructure management. To effectively use Heroku, it’s crucial to understand its app lifecycle. The lifecycle consists of several distinct stages that an application undergoes from development to deployment and beyond.</p>
<p>Get a high-level understanding of the Heroku app lifecycle with this article, or choose a <a href="https://devcenter.heroku.com/start">Getting Started guide</a> to get hands-on understanding. Learn even more in <a href="https://devcenter.heroku.com/articles/how-heroku-works">How Heroku Works</a>.</p>
<h2 id="1-develop-the-app">1. Develop the App</h2>
<p>During the development phase, write the code and create an empty app on Heroku to deploy to it.</p>
<p>You must also <a href="https://devcenter.heroku.com/articles/preparing-a-codebase-for-heroku-deployment">prepare the app for deployment</a>. While you don’t need to make many changes to run your app on Heroku, you must tell the platform which parts of your app are runnable.</p>
<p>If you use common language idioms or frameworks, Heroku can figure it out. For example, in Node.js it’s the <code>main</code> field in <code>package.json</code>. For other apps, or to declare multiple process types to execute, you must declare them in a text file called a <a href="https://devcenter.heroku.com/articles/procfile">Procfile</a>.</p>
<p>Other common practices during development include <a href="https://devcenter.heroku.com/articles/development-configuration#dependencies">integrating dependencies</a>, installing <a href="https://devcenter.heroku.com/articles/add-ons">add-ons</a> for backing services like databases, and <a href="https://devcenter.heroku.com/articles/heroku-local">running applications locally</a>.</p>
<h2 id="2-push-code-to-heroku">2. Push Code to Heroku</h2>
<p>The complete deployment process consists of pushing your code, which triggers a build, that then gets deployed in the form of a release to run on the Heroku platform.</p>
<p>Heroku simplifies the deployment process through Git-based deployment and CI/CD integrations. How you push code depends on your <a href="https://devcenter.heroku.com/categories/deployment">method of deployment</a>, with <a href="https://devcenter.heroku.com/articles/git#deploy-your-code"><code>git push heroku main</code></a> and the <a href="https://devcenter.heroku.com/articles/github-integration">GitHub integration</a> being the most popular.</p>
<h2 id="3-build-the-app">3. Build the App</h2>
<p>When the Heroku platform receives the source code, it initiates a build of the source application.
Heroku supports multiple <a href="https://devcenter.heroku.com/articles/buildpacks">buildpacks</a>, which help configure the environment and dependencies for different languages, such as Node.js, Python, Ruby, and Java. For most apps, we automatically detect which buildpack to use.</p>
<p>The build mechanism is typically language-specific, but it follows the same pattern. It typically retrieves the specified dependencies and creates any necessary assets, such as processing style sheets or compiling code. The resulting build artifact contains your compiled, assembled application, ready to run, together with the instructions, the <a href="https://devcenter.heroku.com/articles/procfile">Procfile</a>, of what you want to execute.</p>
<div class="callout">
<p>When performing a build for Fir-generation apps, we maintain a copy of the application source code solely for the purpose of facilitating user deployments. This copy updates with each build to reflect the most recent version.</p>
</div>
<h2 id="4-deploy-the-release">4. Deploy the Release</h2>
<p>A successful app build triggers the creation of a new <a href="https://devcenter.heroku.com/articles/releases">release</a>. Before creating the new release, Heroku runs any tasks that are specified in the <a href="https://devcenter.heroku.com/articles/release-phase">release phase</a>, if applicable.</p>
<p>If you have a successful app build, and all applicable release phase tasks successfully, Heroku deploys the release. If you use <a href="https://devcenter.heroku.com/articles/heroku-ci">Heroku CI</a> or other CI/CD integration tools, you can require that your test run pass before deployment.
Beyond pushing code, Heroku also creates a new release and restarts your app if you change a <a href="https://devcenter.heroku.com/articles/config-vars">config var</a>, or <a href="https://devcenter.heroku.com/articles/managing-add-ons">modify your app’s add-on resources</a>.</p>
<p>Your release deploys to all app dynos, with Heroku’s <a href="https://devcenter.heroku.com/articles/preboot">Preboot</a> and <a href="https://devcenter.heroku.com/articles/rolling-deploys">Rolling Deploys</a> features enabling zero downtime deployments. To test your app thoroughly before making changes to production, consider using the <a href="https://devcenter.heroku.com/articles/github-integration-review-apps">Review Apps</a> and <a href="https://devcenter.heroku.com/articles/pipelines">Pipelines</a> features to <a href="https://devcenter.heroku.com/articles/pipelines#deployment-with-pipelines">promote builds instead</a>.</p>
<h2 id="5-run-the-app">5. Run the App</h2>
<p>By default, apps are accessible at their <a href="https://devcenter.heroku.com/articles/app-names-and-subdomains">Heroku domains</a>.
After deployment, the application enters the runtime phase, where it runs on compute resources called <a href="https://devcenter.heroku.com/articles/dynos">dynos</a> that actively serve requests. Depending on your dyno formation, some of your dynos run the command associated with the <code>web</code> process type, and some run other commands as declared in your <a href="https://devcenter.heroku.com/articles/procfile">Procfile</a>.</p>
<p>The <code>web</code> dynos are the only ones that receive HTTP traffic. Heroku’s <a href="https://devcenter.heroku.com/articles/http-routing">HTTP routers</a> distribute incoming requests for your application across your running web dynos. This routing handles both HTTP and HTTPS traffic, and it supports multiple simultaneous connections and timeout handling.</p>
<p>The dyno manager is a part of the platform that is responsible for running dynos. Its jobs include cycling, or restarting, dynos when it detects a fault in the running application or problems with the underlying hardware. It also cycles dynos on a daily basis to help maintain the health of applications, unless configured otherwise.</p>
<h2 id="6-scale-the-resources">6. Scale the Resources</h2>
<p>Scaling an app’s capacity to handle web traffic generally involves scaling the number of <code>web</code> dynos. You can also scale up other process types, such as <code>worker</code> dynos for handling your <a href="https://devcenter.heroku.com/articles/background-jobs-queueing">background jobs</a>.
Heroku offers a robust [scaling model with <a href="https://devcenter.heroku.com/articles/dyno-sizes">multiple dyno sizes</a> so you can adjust resources as needed:</p>
<ul>
<li>Horizontal scaling: <a href="https://devcenter.heroku.com/articles/scaling#change-the-number-of-dynos">Adding more dynos</a> to handle increased traffic.</li>
<li>Vertical scaling: <a href="https://devcenter.heroku.com/articles/scaling#change-the-dyno-size">Changing to different sized</a> dynos.</li>
</ul>
<h2 id="7-monitor-the-app">7. Monitor the App</h2>
<p>To ensure the application runs smoothly, monitor its performance and debug issues when necessary. Heroku provides various monitoring tools, such as <a href="https://devcenter.heroku.com/articles/logging">logs</a>, <a href="https://devcenter.heroku.com/articles/metrics">metrics</a>, <a href="https://devcenter.heroku.com/articles/heroku-telemetry">OpenTelemetry</a>(for <a href="https://devcenter.heroku.com/articles/generations#fir">Fir-generation</a> apps only), and support for <a href="https://elements.heroku.com/addons#monitoring">monitoring add-ons</a>.</p>
<h2 id="8-update-and-maintain-the-app">8. Update and Maintain the App</h2>
<p>Applications require regular updates for bug fixes, security patches, and new features. Because Heroku manages and runs applications, the platform takes care of <a href="https://devcenter.heroku.com/articles/platform-updates-maintenance-and-notifications">platform updates and maintenance</a> as well as maintenance for Heroku’s own add-ons, like <a href="https://devcenter.heroku.com/articles/heroku-postgres-maintenance">Heroku Postgres</a>.</p>
<p>Beyond the updates and maintenance provided by Heroku, you can also make any changes you need to your codebase and enter <a href="https://devcenter.heroku.com/articles/maintenance-mode">maintenance mode</a> if you must temporarily disable access to your app. You can also run <a href="https://devcenter.heroku.com/articles/one-off-dynos">one-off dynos</a> to carry out admin tasks.</p>
<h2 id="9-optimize-your-resources">9. Optimize Your Resources</h2>
<p>As you scale, monitor and update your app, find ways to optimize your code and resource usage. See tips on how to optimize your usage in this <a href="https://devcenter.heroku.com/articles/optimizing-resource-costs">guide</a>.</p>
<h2 id="10-decommission-the-app">10. Decommission the App</h2>
<p>When you no longer need an app, <a href="https://devcenter.heroku.com/articles/scaling#change-the-number-of-dynos">scale it down</a>, <a href="https://devcenter.heroku.com/articles/managing-add-ons#destroying-an-add-on">remove its add-ons</a>, and <a href="https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-apps-destroy">delete it</a> from Heroku. Deleting an app is permanent and removes all associated data such as configuration, code, builds and releases with it.</p>
<h2 id="next-steps">Next Steps</h2>
<p>Understanding Heroku’s app lifecycle helps developers make the most of the platform’s features for efficient deployment, scaling, and management. By leveraging Heroku’s streamlined workflow, teams can focus on building and improving their applications without worrying about complex infrastructure management. Dive deeper into any of these topics to learn more:</p>
<ul>
<li><a href="https://devcenter.heroku.com/start">Getting Started Guides</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-local">Running Apps Locally</a></li>
<li><a href="https://devcenter.heroku.com/articles/preparing-a-codebase-for-heroku-deployment">Prepare a Codebase for Deployment</a></li>
<li><a href="https://devcenter.heroku.com/articles/buildpacks">Buildpacks</a></li>
<li><a href="https://devcenter.heroku.com/categories/deployment">Deployment</a></li>
<li><a href="https://devcenter.heroku.com/articles/releases">Releases</a> and <a href="https://devcenter.heroku.com/articles/release-phase">Release Phase</a></li>
<li><a href="https://devcenter.heroku.com/articles/scaling">Scaling Your Dyno Formation</a></li>
<li><a href="https://devcenter.heroku.com/articles/monitoring-apps">Monitoring Heroku Apps</a></li>
<li><a href="https://devcenter.heroku.com/articles/optimizing-resource-costs">Optimizing Resource Costs</a></li>
</ul>tag:devcenter.heroku.com,2005:Article/170752025-09-15T16:39:35Z2025-09-25T14:20:52ZHeroku AI Studio<p>Heroku AI Studio is a web-based interface that enables developers to explore, test, and understand the capabilities of the <a href="https://devcenter.heroku.com/articles/heroku-inference">Managed Inference and Agents add-on</a>. AI Studio offers a real-time, no-code environment where you can interact with underlying models and tools. You can use AI Studio to prototype and optimize AI-powered features before you implement them. AI Studio enables you to streamline and accelerate your development process, helping you get the most value out of the Managed Inference and Agents add-on.</p>
<h2 id="use-cases-and-benefits">Use Cases and Benefits</h2>
<p>AI Studio supports AI development, from model experimentation to integration:</p>
<ul>
<li>Understand model nuances: Experiment with different prompts and parameters to understand the capabilities of the <a href="https://devcenter.heroku.com/articles/heroku-inference-api-model-cards">model</a> you provisioned.</li>
<li>Tune prompts: Tune and refine prompts for your application before you implement them. Tuning enables you to iterate on your text and instructions without frequently redeploying code.</li>
<li>Manage tool use: Verify which tools are effective for your use case, so you can receive reliable and expected outputs.</li>
<li>Streamline integration: Integrate validated prompts and configurations into your app’s code with the help of built-in guidance and code snippets.</li>
</ul>
<h2 id="get-started-with-ai-studio">Get Started with AI Studio</h2>
<p>To access AI Studio:</p>
<ol>
<li>Open the <a href="https://dashboard.heroku.com/">Heroku Dashboard</a>.</li>
<li>Select the app that has the Managed Inference and Agents add-on attached.</li>
<li>Select the <strong><code>Resources</code></strong> tab.</li>
<li>Select <strong><code>Heroku Managed Inference and Agents</code></strong> under <strong><code>Add-on Services</code></strong>. If you don’t have the add-on yet, use the search bar to find and add the Heroku Managed Inference and Agents add-on.</li>
<li>Select <strong><code>Open Playground</code></strong>.</li>
</ol>
<p><img src="https://assets.devcenter.heroku.com/article-images/1757714038-heroku-ai-studio-welcome-1.jpg" alt="Heroku AI Studio welcome page" title="Heroku AI Studio welcome page"></p>
<h2 id="using-ai-studio">Using AI Studio</h2>
<p>You can use the chat function in Heroku AI Studio to ask questions, analyze data, and get general help with Heroku apps. AI Studio can help with a variety of tasks, like analyzing app performance, debugging production issues, and optimizing configurations.</p>
<p>You can change <strong><code>Parameters</code></strong> to guide the AI’s behavior and responses:</p>
<ul>
<li>System Prompt: instructions that guide the AI’s behavior and responses</li>
<li>Temperature: sets the randomness of responses</li>
<li>Top-p: nucleus sampling that limits the model to the most probable tokens</li>
<li>Max tokens: sets response length</li>
<li>Stop sequences: text patterns that stop generation immediately</li>
</ul>
<p>When you chat with AI Studio, you can toggle <strong><code>Agent Mode</code></strong> on and off. Agent mode allows you to use tools. To enable Heroku tool use, click <strong><code>Tools</code></strong> in the upper-right corner. You can use tools for tasks like code execution, content conversion, computation, and database querying.</p>
<p><img src="https://devcenter2.assets.heroku.com/article-images/1757713128-heroku-ai-studio-toolbar.jpg" alt="Heroku AI Studio toolbar" title="Heroku AI Studio toolbar"></p>
<p>Select the moon (or sun) icon to switch between light and dark modes. Click <strong><code>View code</code></strong> to copy code snippets you can integrate into your app.</p>
<h2 id="additional-resources">Additional Resources</h2>
<ul>
<li><a href="https://devcenter.heroku.com/categories/heroku-inference">Heroku Inference</a></li>
<li><a href="https://devcenter.heroku.com/categories/ai">Heroku AI</a></li>
</ul>tag:devcenter.heroku.com,2005:Article/170632025-09-11T21:16:16Z2025-09-11T21:16:16ZPydantic AI Integration<p><a href="https://ai.pydantic.dev/">Pydantic AI</a> is a Python agent framework that enables developers to build production-grade applications and agents with generative AI. You can use Heroku’s Pydantic AI integration for various use cases, including advanced tooling, Model Context Protocol (MCP) and Agent2Agent protocol (A2A), and modular, agentic workflows that support enterprise demands.</p>
<h2 id="setup-and-configuration">Setup and Configuration</h2>
<p>Set the <code>INFERENCE_KEY</code> to the API key and <code>INFERENCE_URL</code> to the base URL with <a href="https://devcenter.heroku.com/articles/config-vars">environment variables</a>:</p>
<pre class="language-bash"><code class="language-bash">export INFERENCE_KEY='your-heroku-api-key'
export INFERENCE_URL='https://us.inference.heroku.com'
</code></pre>
<p>Then, configure the Pydantic AI agent:</p>
<pre class="language-bash"><code class="language-bash">from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIModel
from pydantic_ai.providers.heroku import HerokuProvider
model = OpenAIModel(
'claude-4-sonnet',
provider=HerokuProvider(api_key='your-heroku-inference-key'),
)
agent = Agent(model)
</code></pre>
<h2 id="mcp">MCP</h2>
<p>You can use Heroku Managed Inference and Agents and Pydantic AI to create agentic workflows with <a href="https://devcenter.heroku.com/articles/heroku-inference-tools">built-in tools</a> and <a href="https://devcenter.heroku.com/articles/heroku-inference-working-with-mcp">tool calling with MCP</a>.</p>
<ul>
<li><p>MCP Client: Pydantic AI agents can act as an <a href="https://ai.pydantic.dev/mcp/client/">MCP Client</a>, connecting to MCP servers to use their tools.</p></li>
<li><p>MCP Server: Agents can be exposed as <a href="https://ai.pydantic.dev/mcp/server/">MCP servers</a>, allowing other agents to use them as tools.</p></li>
</ul>
<h2 id="a2a">A2A</h2>
<p>Pydantic’s <a href="https://ai.pydantic.dev/a2a/#fasta2a">FastA2A</a> library simplifies implementation of <a href="https://ai.pydantic.dev/a2a/">A2A protocol</a> in Python. To expose a Pydantic AI agent as an A2A server:</p>
<pre class="language-bash"><code class="language-bash">from pydantic_ai import Agent
agent = Agent('HerokuProvider:claude-4-sonnet', instructions='Be fun!')
app = agent.to_a2a()
</code></pre>
<p>Then, run the example with <a href="https://www.uvicorn.org/">uvicorn</a>:</p>
<pre class="language-bash"><code class="language-bash">uvicorn agent_to_a2a:app --host 0.0.0.0 --port 8000
</code></pre>
<h2 id="additional-resources">Additional Resources</h2>
<ul>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference">Managed Inference and Agents Add-on</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference-working-with-mcp">Working With MCP on Heroku</a></li>
<li><a href="https://devcenter.heroku.com/categories/ai-integrations">AI Integrations</a></li>
</ul>tag:devcenter.heroku.com,2005:Article/115122025-09-04T06:45:26Z2025-10-09T18:30:51ZManaged Inference and Agents API with OpenAI gpt-oss-120b<p>OpenAI’s <a href="https://openai.com/index/introducing-gpt-oss/">gpt-oss-120b</a> is an open-weight, text-to-text large language model (LLM) that supports both conversational chat and tool-calling. It offers a powerful, transparent, and accessible solution you can customize to run your AI workflows.</p>
<ul>
<li><strong>Model ID:</strong> <code>openai-gpt-oss-120b</code></li>
<li><strong>Region:</strong> <code>us</code></li>
</ul>
<h2 id="when-to-use-this-model">When to Use This Model</h2>
<p>OpenAI’s <a href="https://platform.openai.com/docs/models/gpt-oss-120b">gpt-oss-120b</a> is well-suited for natural language understanding, code generation, and complex problem-solving. It’s open-weight and can be fine-tuned to support various use cases.</p>
<h2 id="usage">Usage</h2>
<p>OpenAI’s gpt-oss-120b follows our <a href="https://devcenter.heroku.com/articles/heroku-inference-api-v1-chat-completions">/v1/chat/completions API schema</a>.</p>
<p>To provision access to the model, attach <code>openai-gpt-oss-120b</code> to your app <code>$APP_NAME</code>:</p>
<pre class="language-bash"><code class="language-bash">heroku ai:models:create -a $APP_NAME openai-gpt-oss-120b
</code></pre>
<p>You can invoke <code>openai-gpt-oss-120b</code> in a variety of ways:</p>
<ul>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference-cli-commands">Heroku CLI <code>ai</code> plugin</a> (<code>heroku ai:models:call</code>)</li>
<li><a href="#example-curl-request">curl</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference-quickstart-python-v1-chat-completions">Python</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference-quickstart-ruby-v1-chat-completions">Ruby</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-inference-quickstart-javascript-v1-chat-completions">Javascript</a></li>
</ul>
<h3 id="rate-limits">Rate Limits</h3>
<ul>
<li>Maximum requests per minute: 200</li>
<li>Maximum tokens per minute: 800,000</li>
</ul>
<h3 id="example-curl-request">Example curl Request</h3>
<p>Get started quickly with an example request:</p>
<pre class="language-bash"><code class="language-bash">export INFERENCE_MODEL_ID=$(heroku config:get -a example-app INFERENCE_MODEL_ID)
export INFERENCE_KEY=$(heroku config:get -a example-app INFERENCE_KEY)
export INFERENCE_URL=$(heroku config:get -a example-app INFERENCE_URL)
curl $INFERENCE_URL/v1/chat/completions \
-H "Authorization: Bearer $INFERENCE_KEY" \
-d @- <<EOF
{
"model": "$INFERENCE_MODEL_ID",
"messages": [
{ "role": "user", "content": "Hello!" },
{ "role": "assistant", "content": "Hi there! How can I assist you today?" },
{ "role": "user", "content": "What's the weather like in Portland, Oregon right now?" }
],
"temperature": 0.5,
"max_tokens": 100,
"stream": false,
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Fetches the current weather for a given city.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The name of the city to get weather for."
}
},
"required": ["city"]
}
}
}
],
"tool_choice": "auto",
"top_p": 0.9
}
EOF
</code></pre>
<!--fix devcenter error-->tag:devcenter.heroku.com,2005:Article/115112025-08-29T17:11:31Z2025-09-27T11:11:27ZHeroku OpenTelemetry Signals and Attributes Reference<p>This article covers Heroku’s OpenTelemetry (OTel) signals and attributes. If you’re new to OpenTelemetry, additional articles are available:</p>
<ul>
<li><a href="https://devcenter.heroku.com/articles/heroku-telemetry">Heroku OpenTelemetry</a></li>
<li><a href="https://devcenter.heroku.com/articles/opentelemetry-concepts-and-heroku">OpenTelemetry Concepts and Heroku</a></li>
<li><a href="https://devcenter.heroku.com/articles/working-with-heroku-telemetry-drains">Working with Heroku Telemetry Drains</a></li>
</ul>
<h2 id="signals">Signals</h2>
<p>Heroku Telemetry provides comprehensive observability for your applications by leveraging the <a href="https://opentelemetry.io/">OpenTelemetry</a> framework. We deliver a complete view by collecting signals from the following sources:</p>
<ul>
<li><strong>Application telemetry</strong>: Heroku provides application metrics for all running applications by default. Users can also send additional traces, metrics, and logs from their applications via an OpenTelemetry gRPC or HTTP exporters, as well as all <code>stdout</code> and <code>stderr</code> logs.</li>
<li><strong>First-party services telemetry</strong>: We provide visibility into Heroku’s own services and add-ons. We provide logs from the Heroku Platform API, metrics, traces, and logs from the Heroku Router. We also provide logs from add-ons such as Heroku Key-Value, Heroku Postgres, Heroku Scheduler, and Apache Kafka on Heroku.</li>
</ul>
<p>For additional language-specific telemetry data, instrument your application with one of the <a href="https://opentelemetry.io/docs/languages/">open-source SDKs</a>.</p>
<p>An attribute provides additional context or metadata about a signal. The availability of the following signals and attributes depends on your application’s configuration:</p>
<h2 id="common-resource-attributes">Common Resource Attributes</h2>
<p>These attributes are automatically added to all application signals at the resource attribute level and aren’t user-configurable.</p>
<div class="warning">
<p>Although you can set these attributes at the log, metric, or trace level, be aware that your values may override the resource-level attributes when exporting these signals.</p>
</div>
<h3 id="service-attributes">Service Attributes</h3>
<p>Heroku provides comprehensive out-of-the-box telemetry, ensuring consistency by adhering to <a href="https://opentelemetry.io/docs/specs/semconv/">Semantic Conventions</a>. <a href="https://opentelemetry.io/docs/specs/semconv/registry/attributes/service/">Service</a> level attributes are automatically added to all telemetry, which users can configure within their applications.</p>
<p>For application telemetry, it is possible to set service-level attributes using OpenTelemetry (OTel) exporters within application code to export traces, logs, and metrics. However, we recommend configuring these attributes on the application itself by setting the <code>OTEL_RESOURCE_ATTRIBUTES</code> and <code>OTEL_SERVICE_NAME</code> config variables. You can’t customize first-party service signals.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>service.instance.id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier for dyno</td>
<td style="text-align: left"><code>"web-12a34bcd56-7efgh"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service name of application, if not set, defaults to application name</td>
<td style="text-align: left"><code>"my-service-app"</code></td>
<td style="text-align: left">yes, and Heroku provides default</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.namespace</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">namespace name for service name</td>
<td style="text-align: left"><code>"my-test-namespace"</code></td>
<td style="text-align: left">yes, and Heroku provides default</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.version</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">version of app release when telemetry generated</td>
<td style="text-align: left"><code>"v19"</code></td>
<td style="text-align: left">yes, and Heroku provides default</td>
</tr>
</tbody></table>
<h3 id="heroku-cloud-provider-attributes">Heroku Cloud Provider Attributes</h3>
<p>In addition to the Service attributes described above, Heroku automatically adds Cloud Provider specific information to all telemetry data. These attributes are fixed and aren’t customizable unless specified.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>cloud.provider</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">name of cloud provider, appears on all signals</td>
<td style="text-align: left"><code>"heroku"</code></td>
<td style="text-align: left">no, Heroku-provided default</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier of app</td>
<td style="text-align: left"><code>"9daa2797-e49b-4624-932f-ec3f9688e3da"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">name of application</td>
<td style="text-align: left"><code>"test-app"</code></td>
<td style="text-align: left">yes, set on application creation or renaming</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.release.id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier of app release</td>
<td style="text-align: left"><code>"release-afc4d88c-7d89-4bc6-b364-7658cd60ba57"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.release.version</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">version of app release when telemetry is generated</td>
<td style="text-align: left"><code>"v19"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.workload.id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">workload identifier, as defined by the process type</td>
<td style="text-align: left"><code>"web"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<h2 id="application-telemetry">Application Telemetry</h2>
<h3 id="dyno-runtime-metrics">Dyno Runtime Metrics</h3>
<p>Heroku captures dyno-level metrics. We follow the semantic convention for <a href="https://opentelemetry.io/docs/specs/semconv/system/container-metrics/">container metrics</a>.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>container.cpu.usage</strong></td>
<td style="text-align: left"><em>gauge</em></td>
<td style="text-align: left">dyno CPU usage, as a percentage of capacity</td>
<td style="text-align: left"><code>0.00029895</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>container.memory.available</strong></td>
<td style="text-align: left"><em>gauge</em></td>
<td style="text-align: left">dyno memory available, in bytes</td>
<td style="text-align: left"><code>530911232</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>container.memory.usage</strong></td>
<td style="text-align: left"><em>gauge</em></td>
<td style="text-align: left">dyno total memory usage, in bytes</td>
<td style="text-align: left"><code>6291456</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>container.uptime</strong></td>
<td style="text-align: left"><em>sum</em></td>
<td style="text-align: left">time elapsed since dyno started, in seconds</td>
<td style="text-align: left"><code>348223</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<p>Example of a JSON dyno metric:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":null,
"resource_attributes":{
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"heroku.workload.id":"web",
"heroku.release.version":"v6",
"service.version":"v6",
"heroku.release.id":"release-3bd90b80-16a1-4f5b-9465-a61e1b7464d4",
"cloud.provider":"heroku",
"service.instance.id":"web-67dbf78464-q6kc6",
"heroku.app.name":"test-app",
"service.namespace":"test-namespace",
"service.name":"test-app"
},
"scope_metrics":[
{
"scope_schema_url":null,
"instrumentation_scope":"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kubeletstatsreceiver 0.0.9",
"metrics":[
{
"descriptor":{
"name":"container.memory.available",
"description":"Container memory available",
"unit":"By",
"data_type":"Gauge"
},
"number_data_points":[
{
"start_timestamp":"2025-08-13T20:23:20Z",
"timestamp":"2025-08-13T20:45:15.767066105Z",
"value":460095488
}
]
},
{
"descriptor":{
"name":"container.memory.usage",
"description":"Container memory usage",
"unit":"By",
"data_type":"Gauge"
},
"number_data_points":[
{
"start_timestamp":"2025-08-13T20:23:20Z",
"timestamp":"2025-08-13T20:45:15.767066105Z",
"value":76775424
}
]
},
{
"descriptor":{
"name":"container.uptime",
"description":"The time since the container started",
"unit":"s",
"data_type":"Sum",
"is_monotonic":true,
"aggregation_temporality":"Cumulative"
},
"number_data_points":[
{
"start_timestamp":"2025-08-13T20:23:20Z",
"timestamp":"2025-08-13T20:45:15.767066105Z",
"value":1315
}
]
},
{
"descriptor":{
"name":"container.cpu.usage",
"description":"Container cpu utilization as a ratio of the container's limits",
"unit":"1",
"data_type":"Gauge"
},
"number_data_points":[
{
"start_timestamp":"2025-08-13T20:23:20Z",
"timestamp":"2025-08-13T20:45:15.767066105Z",
"value":0.001771
}
]
}
]
}
]
}
</code></pre>
<h2 id="router-signals">Router Signals</h2>
<p>The <a href="https://devcenter.heroku.com/articles/http-routing">Heroku Router</a> manages web application traffic, automatically directing incoming HTTP requests to the appropriate web <a href="https://devcenter.heroku.com/articles/dynos">dynos</a> within the Heroku platform. The router emits various signals.</p>
<h3 id="router-trace-spans">Router Trace Spans</h3>
<p>Router traces always have the <code>service.name</code> attribute set to <code>heroku-router</code>. They include standard Heroku attributes, along with specific additions relevant to the request.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>client.address</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">IP address of forwarding client</td>
<td style="text-align: left">“204.14.236.213”</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.router.connect</strong></td>
<td style="text-align: left"><em>double</em></td>
<td style="text-align: left">time taken to establish connection, in milliseconds</td>
<td style="text-align: left">0.000873262</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.router.service</strong></td>
<td style="text-align: left"><em>double</em></td>
<td style="text-align: left">time taken to service the request, in milliseconds</td>
<td style="text-align: left">0.000621714</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>http.request.method</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">type of data request</td>
<td style="text-align: left">“GET”</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>http.response.status_code</strong></td>
<td style="text-align: left"><em>integer</em></td>
<td style="text-align: left">HTTP status code</td>
<td style="text-align: left">200</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>http.response.body.size</strong></td>
<td style="text-align: left"><em>integer</em></td>
<td style="text-align: left">size of response, in bytes</td>
<td style="text-align: left">8826</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>server.address</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">host identifier the HTTP request is sent to</td>
<td style="text-align: left">“example-app.com”</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>tls.protocol.version</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">version of TLS protocol</td>
<td style="text-align: left">“tls1.3”</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<p>Example of a JSON router trace:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":"https://opentelemetry.io/schemas/1.6.1",
"resource_attributes":{
"heroku.dyno.id":"web-67dbf78464-q6kc6",
"service.instance.id":"web-67dbf78464-q6kc6",
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"heroku.workload.id":"web",
"heroku.release.version":"v6",
"service.version":"v6",
"heroku.release.id":"release-3bd90b80-16a1-4f5b-9465-a61e1b7464d4",
"cloud.provider":"heroku",
"heroku.app.name":"test-app",
"service.namespace":"test-namespace",
"service.name":"test-app"
},
"scope_spans":[
{
"scope_schema_url":null,
"instrumentation_scope":"heroku-router",
"spans":[
{
"trace_id":"4b26d26a52bcf26c31f9637a350c5df9",
"parent_id":null,
"id":"147c90133ba98656",
"name":"customer.request",
"kind":"internal",
"start_time":"2025-08-13T21:18:57.589468318Z",
"end_time":"2025-08-13T21:18:57.59109646Z",
"status_code":1,
"status_message":null,
"attributes":{
"client.address":"20.171.207.158",
"duration_ms":1.628142,
"heroku.router.connect":0.000873262,
"heroku.router.service":0.000621714,
"http.request.method":"GET",
"http.response.body.size":19,
"http.response.status_code":404,
"network.protocol.name":"http",
"server.address":"test-app-996f3244724d.redbud-virginia.herokuapp.com",
"span.num_events":0,
"span.num_links":0,
"tls.protocol.version":"tls1.3",
"type":"internal",
"url.path":"/",
"url.query":""
}
}
]
}
]
}
</code></pre>
<h3 id="router-metrics">Router Metrics</h3>
<p>Router metrics offer request duration statistics, including the standard common attributes, as well as the following attributes. The <code>service.name</code> is always <code>heroku-router</code>.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>http.server.request.duration</strong></td>
<td style="text-align: left"><em>histogram</em></td>
<td style="text-align: left">duration of the incoming HTTP server requests, in milleseconds</td>
<td style="text-align: left"></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<p>Example of a JSON router metrics:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":"https://opentelemetry.io/schemas/1.6.1",
"resource_attributes":{
"service.instance.id":"web-67dbf78464-q6kc6",
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"heroku.workload.id":"web",
"heroku.release.version":"v6",
"service.version":"v6",
"heroku.release.id":"release-3bd90b80-16a1-4f5b-9465-a61e1b7464d4",
"cloud.provider":"heroku",
"heroku.app.name":"test-app",
"service.namespace":"test-namespace",
"service.name":"test-app"
},
"scope_metrics":[
{
"scope_schema_url":null,
"instrumentation_scope":"otel-logger",
"metrics":[
{
"descriptor":{
"name":"http.server.request.duration",
"description":"The duration of incoming HTTP requests.",
"unit":"ms",
"data_type":"Histogram"
},
"summary_data_points":[
{
"time":"2025-08-13T21:19:27Z",
"sum":0.001518499,
"count":1,
"quantile_values":[
{
"quantile":0.001,
"value":0.0015184986321850637
},
{
"quantile":0.01,
"value":0.0015184986321850637
},
{
"quantile":0.05,
"value":0.0015184986321850637
},
{
"quantile":0.1,
"value":0.0015184986321850637
},
{
"quantile":0.2,
"value":0.0015184986321850637
},
{
"quantile":0.25,
"value":0.0015184986321850637
},
{
"quantile":0.5,
"value":0.0015184986321850637
},
{
"quantile":0.75,
"value":0.0015184986321850637
},
{
"quantile":0.8,
"value":0.0015184986321850637
},
{
"quantile":0.9,
"value":0.0015184986321850637
},
{
"quantile":0.95,
"value":0.0015184986321850637
},
{
"quantile":0.99,
"value":0.0015184986321850637
},
{
"quantile":0.999,
"value":0.0015184986321850637
}
]
}
]
}
]
}
]
}
</code></pre>
<h3 id="router-logs">Router Logs</h3>
<p>Router logs include standard Heroku attributes in addition to the following attributes. The <code>service.name</code> is always <code>heroku-router</code>.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>body</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">body of router log</td>
<td style="text-align: left">“at=info method=GET path=\”/js/twint_ch.js\“ …”</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>span_id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier of processing span</td>
<td style="text-align: left">“051581bf3cb55c13”,</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>trace_id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier of trace</td>
<td style="text-align: left">“a7d348b6311009c36dda66fd7e6b0685”</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_number</strong></td>
<td style="text-align: left"><em>integer</em></td>
<td style="text-align: left">numerical value of severity</td>
<td style="text-align: left">9</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_text</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">severity of an event <br><strong>eg</strong>: “Critical”, “Warning”, or “Info”</td>
<td style="text-align: left">“Info”</td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<p>Example of a JSON router logs:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":"https://opentelemetry.io/schemas/1.6.1",
"resource_attributes":{
"service.instance.id":"web-67dbf78464-q6kc6",
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"heroku.workload.id":"web",
"heroku.release.version":"v6",
"service.version":"v6",
"heroku.release.id":"release-3bd90b80-16a1-4f5b-9465-a61e1b7464d4",
"cloud.provider":"heroku",
"heroku.app.name":"test-app",
"service.namespace":"test-namespace",
"service.name":"test-app"
},
"scope_logs":[
{
"scope_schema_url":null,
"instrumentation_scope":"otel-logger",
"log_records":[
{
"observed_timestamp":"2025-08-13T21:18:57.590973861Z",
"timestamp":"2025-08-13T21:18:57.590973861Z",
"severity_text":"info",
"severity_number":9,
"body":"at=info method=GET path=\"/\" host=test-app-996f3244724d.test.herokuapp.com",
"attributes":{
"library.name":"heroku-router",
"meta.annotation_type":"span_event",
"flags":"1"
},
"trace_id":"4b26d26a52bcf26c31f9637a350c5df9",
"span_id":"147c90133ba98656"
}
]
}
]
}
</code></pre>
<h2 id="heroku-platform-api-logs">Heroku Platform API Logs</h2>
<h3 id="platform-logs">Platform Logs</h3>
<p>Heroku Platform API logs record administrative actions, like dyno scaling and other management commands, performed on applications. To filter all Heroku API Platform signals, use the <code>service.name</code> attribute with the value <code>heroku-api</code>.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>body</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">body of API log</td>
<td style="text-align: left"><code>"Release v6 created by user heroku-postgresql@addons.heroku.com"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>cloud.provider</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">name of cloud provider, appears on all signals</td>
<td style="text-align: left"><code>"heroku"</code></td>
<td style="text-align: left">no, Heroku-provided default</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier of app</td>
<td style="text-align: left"><code>"9daa2797-e49b-4624-932f-ec3f9688e3da"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">application name</td>
<td style="text-align: left"><code>"test-app"</code></td>
<td style="text-align: left">yes, set on application creation or renaming</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service name of the signals source</td>
<td style="text-align: left"><code>"heroku-api"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.namespace</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service namespace of the application</td>
<td style="text-align: left"><code>"test-namespace"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_number</strong></td>
<td style="text-align: left"><em>integer</em></td>
<td style="text-align: left">numerical value of severity</td>
<td style="text-align: left"><code>9</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_text</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">severity of an event <br><strong>eg</strong>: “Critical”, “Warning”, or “Info”</td>
<td style="text-align: left"><code>"Info"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<p>Example of a JSON Heroku Platform API log:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":null,
"resource_attributes":{
"service.name":"heroku-api",
"cloud.provider":"heroku",
"heroku.app.name":"test-app",
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"service.namespace":"test-namespace"
},
"scope_logs":[
{
"scope_schema_url":null,
"instrumentation_scope":null,
"log_records":[
{
"observed_timestamp":"1970-01-01T00:00:00Z",
"timestamp":"2025-08-13T20:58:50Z",
"severity_text":"Info",
"severity_number":9,
"body":"Release v6 created by user heroku-postgresql@addons.heroku.com",
"flags":0
}
]
}
]
}
</code></pre>
<h2 id="other-first-party-service-signals">Other First-Party Service Signals</h2>
<p>Signals relevant to the application are also transmitted from first-party add-ons. These signals, in addition to those directly originating from the application, include a <code>service.name</code> attribute indicating the source service:</p>
<ul>
<li><code>heroku-postgresql</code>: For <a href="#heroku-postgres">Heroku Postgres logs</a></li>
<li><code>heroku-redis</code>: For <a href="#heroku-key-value-store">Heroku Key-Value Store logs</a></li>
<li><code>heroku-kafka</code>: For <a href="#apache-kafka-on-heroku">Apache Kafka on Heroku logs</a></li>
<li><code>scheduler</code>: for <a href="#heroku-scheduler">Heroku Scheduler logs</a></li>
</ul>
<h3 id="heroku-postgres">Heroku Postgres</h3>
<h4 id="postgres-service-and-metric-logs">Postgres Service and Metric Logs</h4>
<p><a href="https://devcenter.heroku.com/articles/heroku-postgresql">Heroku Postgres</a>, a managed SQL database service offered by Heroku, captures all PostgreSQL logs, including executed queries, connections, and instance status. To filter all Heroku Postgres signals, use the <code>service.name</code> attribute with the value <code>heroku-postgresql</code>.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>body</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">body of API log</td>
<td style="text-align: left"><code>"at=info method=GET path=\"/js/twint_ch.js\" ..."</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>cloud.provider</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">name of cloud provider, appears on all signals</td>
<td style="text-align: left"><code>"heroku"</code></td>
<td style="text-align: left">no, Heroku-provided default</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier of app</td>
<td style="text-align: left"><code>"9daa2797-e49b-4624-932f-ec3f9688e3da"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">application name</td>
<td style="text-align: left"><code>"test-app"</code></td>
<td style="text-align: left">yes, set on application creation or renaming</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service name of the signals source</td>
<td style="text-align: left"><code>"heroku-postgresql"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.namespace</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service namespace of the application</td>
<td style="text-align: left"><code>"test-namespace"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_number</strong></td>
<td style="text-align: left"><em>integer</em></td>
<td style="text-align: left">numerical value of severity</td>
<td style="text-align: left"><code>9</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_text</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">severity of an event <br><strong>one of</strong>: “Critical”, “Warning”, or “Info”</td>
<td style="text-align: left"><code>"Info"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<p>Example of a JSON Heroku Postgres log:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":null,
"resource_attributes":{
"service.name":"heroku-postgresql",
"cloud.provider":"heroku",
"heroku.app.name":"test-app",
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"service.namespace":"test-namespace"
},
"scope_logs":[
{
"scope_schema_url":null,
"instrumentation_scope":null,
"log_records":[
{
"observed_timestamp":"1970-01-01T00:00:00Z",
"timestamp":"2025-08-13T20:58:50Z",
"severity_text":"Info",
"severity_number":9,
"body":"source=HEROKU_POSTGRESQL_ORANGE addon=postgresql-curved-71720 sample#service-available=1 sample#current_transaction=774 sample#db_size=7957651bytes sample#db-max-size=68719476736bytes sample#db-size-percentage-used=0.00012 sample#tables=0 sample#active-connections=12 sample#waiting-connections=0 sample#max-connections=200 sample#connections-percentage-used=0.06000 sample#index-cache-hit-rate=0 sample#table-cache-hit-rate=0 sample#load-avg-1m=0.02 sample#load-avg-5m=0.005 sample#load-avg-15m=0.01 sample#read-iops=0 sample#write-iops=0.031579 sample#max-iops=3000 sample#iops-percentage-used=0.00001 sample#tmp-disk-used=543600640 sample#tmp-disk-available=72435191808 sample#memory-total=3944372kB sample#memory-free=2797144kB sample#memory-percentage-used=0.29085 sample#memory-cached=859524kB sample#memory-postgres=24288kB sample#wal-percentage-used=0.04938224410022926 sample#rollback-from=2025-08-19T17:21",
"flags":0
}
]
}
]
}
</code></pre>
<h3 id="heroku-key-value-store">Heroku Key-Value Store</h3>
<h4 id="key-value-metric-logs">Key/Value Metric Logs</h4>
<p>Heroku’s managed key-value store, <a href="https://devcenter.heroku.com/articles/heroku-redis">Heroku Key-Value Store</a>, captures logs that show usage related to the instance. To filter all Heroku Key-Value instance signals, use the <code>service.name</code> attribute with the value <code>heroku-redis</code>.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>body</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">body of API log</td>
<td style="text-align: left"><code>"at=info method=GET path=\"/js/twint_ch.js\" ..."</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>cloud.provider</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">name of cloud provider, appears on all signals</td>
<td style="text-align: left"><code>"heroku"</code></td>
<td style="text-align: left">no, Heroku-provided default</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier of app</td>
<td style="text-align: left"><code>"9daa2797-e49b-4624-932f-ec3f9688e3da"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">application name</td>
<td style="text-align: left"><code>"test-app"</code></td>
<td style="text-align: left">yes, set on application creation or renaming</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service name of the signals source</td>
<td style="text-align: left"><code>"heroku-redis"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.namespace</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service namespace of the application</td>
<td style="text-align: left"><code>"test-namespace"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_number</strong></td>
<td style="text-align: left"><em>integer</em></td>
<td style="text-align: left">numerical value of severity</td>
<td style="text-align: left"><code>9</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_text</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">severity of an event <br><strong>eg</strong>: “Critical”, “Warning”, or “Info”</td>
<td style="text-align: left"><code>"Info"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<p>Example of a JSON Heroku Key-Value Store log:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":null,
"resource_attributes":{
"service.name":"heroku-redis",
"cloud.provider":"heroku",
"heroku.app.name":"test-app",
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"service.namespace":"test-namespace"
},
"scope_logs":[
{
"scope_schema_url":null,
"instrumentation_scope":null,
"log_records":[
{
"observed_timestamp":"1970-01-01T00:00:00Z",
"timestamp":"2025-08-13T20:58:50Z",
"severity_text":"Info",
"severity_number":9,
"body":"source=REDIS addon=redis-amorphous-75821 sample#active-connections=1 sample#max-connections=18 sample#connection-percentage-used=0.05556 sample#load-avg-1m=0.51 sample#load-avg-5m=0.56 sample#load-avg-15m=0.57 sample#read-iops=0 sample#write-iops=0 sample#max-iops=3000 sample#iops-percentage-used=0.00000 sample#memory-total=16167808kB sample#memory-free=6787836kB sample#memory-percentage-used=0.58016 sample#memory-cached=3235532kB sample#memory-redis=4782496bytes sample#hit-rate=1 sample#evicted-keys=0",
"flags":0
}
]
}
]
}
</code></pre>
<h3 id="apache-kafka-on-heroku">Apache Kafka on Heroku</h3>
<h4 id="kafka-service-and-metric-logs">Kafka Service and Metric Logs</h4>
<p><a href="https://devcenter.heroku.com/articles/kafka-on-heroku">Apache Kafka on Heroku</a> is a Kafka-as-a-service solution integrated with the Heroku platform. It provides detailed logs, capturing metrics and log lines directly from your Kafka cluster. To filter all Apache Kafka on Heroku signals, use the <code>service.name</code> attribute with the value <code>heroku-kafka</code>.</p>
<table><thead>
<tr>
<th style="text-align: left">Name</th>
<th style="text-align: left">Type</th>
<th style="text-align: left">Description</th>
<th style="text-align: left">Example</th>
<th style="text-align: left">User-Configurable</th>
</tr>
</thead><tbody>
<tr>
<td style="text-align: left"><strong>body</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">body of API log</td>
<td style="text-align: left"><code>"at=info method=GET path=\"/js/twint_ch.js\" ..."</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>cloud.provider</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">name of cloud provider, appears on all signals</td>
<td style="text-align: left"><code>"heroku"</code></td>
<td style="text-align: left">no, Heroku-provided default</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.id</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">unique identifier of app</td>
<td style="text-align: left"><code>"9daa2797-e49b-4624-932f-ec3f9688e3da"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>heroku.app.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">application name</td>
<td style="text-align: left"><code>"test-app"</code></td>
<td style="text-align: left">yes, set on application creation or renaming</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.name</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service name of the signals source</td>
<td style="text-align: left"><code>"heroku-kafka"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>service.namespace</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">service namespace of the application</td>
<td style="text-align: left"><code>"test-namespace"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_number</strong></td>
<td style="text-align: left"><em>integer</em></td>
<td style="text-align: left">numerical value of severity</td>
<td style="text-align: left"><code>9</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
<tr>
<td style="text-align: left"><strong>severity_text</strong></td>
<td style="text-align: left"><em>string</em></td>
<td style="text-align: left">severity of an event <br><strong>eg</strong>: “Critical”, “Warning”, or “Info”</td>
<td style="text-align: left"><code>"Info"</code></td>
<td style="text-align: left">no, Heroku-provided value</td>
</tr>
</tbody></table>
<p>Example of a JSON Apache Kafka on Heroku log:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":null,
"resource_attributes":{
"service.name":"heroku-kafka",
"cloud.provider":"heroku",
"heroku.app.name":"test-app",
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"service.namespace":"test-namespace"
},
"scope_logs":[
{
"scope_schema_url":null,
"instrumentation_scope":null,
"log_records":[
{
"observed_timestamp":"1970-01-01T00:00:00Z",
"timestamp":"2025-08-13T20:58:50Z",
"severity_text":"Info",
"severity_number":9,
"body":"source=KAFKA addon=kafka-defined-62412 sample#load-avg-1m=0.015 sample#load-avg-5m=0.0425 sample#load-avg-15m=0.0225 sample#read-iops=0 sample#write-iops=0.32099 sample#memory-total=16083140kB sample#memory-free=10618472kB sample#memory-percentage-used=0.33978 sample#memory-cached=655372kB sample#bytes-in-per-second=0.0 sample#bytes-out-per-second=0.0",
"flags":0
}
]
}
]
}
</code></pre>
<h3 id="heroku-scheduler">Heroku Scheduler</h3>
<h4 id="scheduler-logs">Scheduler Logs</h4>
<p><a href="https://devcenter.heroku.com/articles/scheduler">Heroku Scheduler</a> is an add-on that allows users to run scheduled jobs on applications, much like cron jobs. All logs generated via scheduled tasks include common resource attributes, and you can filter by the attribute <code>heroku.workload.id</code> with the value <code>scheduler</code>.</p>
<p>Example of a JSON Heroku Scheduler log:</p>
<pre class="language-json"><code class="language-json">{
"resource_schema_url":null,
"resource_attributes":{
"service.instance.id":"scheduler-68d8d6dc59-vhjr9",
"heroku.app.id":"c3d3df33-8afb-4323-ac49-a9bf41a50dd1",
"heroku.workload.id":"scheduler",
"heroku.release.version":"v6",
"service.version":"v6",
"heroku.release.id":"release-3bd90b80-16a1-4f5b-9465-a61e1b7464d4",
"cloud.provider":"heroku",
"heroku.app.name":"test-app",
"service.namespace":"test-namespace",
"service.name":"test-app"
},
"scope_logs":[
{
"scope_schema_url":null,
"instrumentation_scope":null,
"log_records":[
{
"observed_timestamp":"2025-08-13T20:44:39.732192581Z",
"timestamp":"2025-08-13T20:44:39.591629411Z",
"severity_text":"INFO",
"severity_number":9,
"body":"Test task",
"attributes":{
"logtag":"F",
"log.iostream":"stdout"
},
"trace_id":null,
"span_id":null,
"flags":0
}
]
}
]
}
</code></pre>
<h2 id="additional-reading">Additional Reading</h2>
<ul>
<li><a href="https://opentelemetry.io/docs/specs/otel/schemas/">Telemetry Schemas</a></li>
<li><a href="https://opentelemetry.io/docs/specs/semconv/resource/cloud-provider/heroku/">Heroku Dynos Schema</a> (development)</li>
<li><a href="https://devcenter.heroku.com/articles/opentelemetry-concepts-and-heroku">OpenTelemetry Concepts and Heroku</a></li>
<li><a href="https://devcenter.heroku.com/articles/heroku-telemetry">Heroku Telemetry Drains</a></li>
<li><a href="https://devcenter.heroku.com/articles/working-with-heroku-telemetry-drains">Working with Heroku Telemetry Drains</a></li>
</ul>