Skip to main content
This guide shows you how to submit forecasts for different question types using the Metaculus API.

Prerequisites

All API requests require authentication. Make sure you have:
  1. Generated an API token from your account settings
  2. Include the token in the Authorization header: Token YOUR_API_TOKEN

Binary Questions

Binary questions have yes/no outcomes. Submit a probability between 0 and 1.
1

Get the question details

First, retrieve the question to get its ID and confirm it’s a binary question:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Get post details
post_id = 1
response = requests.get(
    f"https://www.metaculus.com/api/posts/{post_id}/",
    headers=headers
)
post_data = response.json()
question = post_data["question"]

print(f"Question ID: {question['id']}")
print(f"Type: {question['type']}")
print(f"Title: {question['title']}")
2

Submit your binary forecast

Submit a probability for the yes outcome:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Submit binary forecast
forecast_data = [
    {
        "question": 1,  # Question ID
        "probability_yes": 0.63
    }
]

response = requests.post(
    "https://www.metaculus.com/api/questions/forecast/",
    headers=headers,
    json=forecast_data
)

if response.status_code == 201:
    print("Forecast submitted successfully!")
else:
    print(f"Error: {response.status_code}")
    print(response.json())

Numeric Questions (Continuous)

Numeric questions require a 201-point CDF (Cumulative Distribution Function). For detailed guidance on generating CDFs, see the Continuous CDF Guide.
1

Get the question scaling

Retrieve the question details to understand its range and scaling:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Get question details
post_id = 3530
response = requests.get(
    f"https://www.metaculus.com/api/posts/{post_id}/",
    headers=headers
)
question = response.json()["question"]

print(f"Type: {question['type']}")
print(f"Range: {question['scaling']['range_min']} to {question['scaling']['range_max']}")
print(f"Unit: {question['unit']}")
print(f"Open lower bound: {question['open_lower_bound']}")
print(f"Open upper bound: {question['open_upper_bound']}")
2

Generate a CDF

Create a 201-point CDF. This example shows a simple approach:
Python
import numpy as np

# For a question with closed bounds (range_min to range_max)
# Generate a simple normal-like distribution
def simple_cdf(mean_location=0.5, spread=0.3):
    """
    Generate a 201-point CDF.
    mean_location: center of distribution (0 to 1)
    spread: how spread out the distribution is
    """
    points = np.linspace(0, 1, 201)
    # Simple sigmoid-based CDF
    cdf = 1 / (1 + np.exp(-(points - mean_location) / spread))
    # Normalize to [0, 1]
    cdf = (cdf - cdf.min()) / (cdf.max() - cdf.min())
    return cdf.tolist()

my_cdf = simple_cdf(mean_location=0.6, spread=0.15)
print(f"CDF has {len(my_cdf)} points")
print(f"First value: {my_cdf[0]:.5f}, Last value: {my_cdf[-1]:.5f}")
For production use, see the Continuous CDF Guide for proper CDF generation that handles:
  • Linear and logarithmic scaling
  • Open and closed bounds
  • Percentile-based distributions
  • CDF standardization and validation
3

Submit your numeric forecast

Submit the CDF to the API:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Submit continuous forecast
forecast_data = [
    {
        "question": 3530,
        "continuous_cdf": my_cdf  # 201-point list
    }
]

response = requests.post(
    "https://www.metaculus.com/api/questions/forecast/",
    headers=headers,
    json=forecast_data
)

if response.status_code == 201:
    print("Forecast submitted successfully!")
else:
    print(f"Error: {response.status_code}")
    print(response.json())

Multiple Choice Questions

For multiple choice questions, provide probabilities for each option that sum to 1.0.
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Submit multiple choice forecast
forecast_data = [
    {
        "question": 20772,
        "probability_yes_per_category": {
            "Democratic": 0.45,
            "Republican": 0.40,
            "Libertarian": 0.08,
            "Green": 0.05,
            "Other": 0.02
        }
    }
]

response = requests.post(
    "https://www.metaculus.com/api/questions/forecast/",
    headers=headers,
    json=forecast_data
)

if response.status_code == 201:
    print("Forecast submitted successfully!")
The probabilities must sum to exactly 1.0, or the API will reject your forecast.

Group of Questions

For posts containing multiple sub-questions, submit forecasts for each one:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Submit forecasts for multiple questions in a group
forecast_data = [
    {"question": 10880, "probability_yes": 0.11},  # 2030
    {"question": 10923, "probability_yes": 0.22},  # 2035
    {"question": 10924, "probability_yes": 0.33}   # 2040
]

response = requests.post(
    "https://www.metaculus.com/api/questions/forecast/",
    headers=headers,
    json=forecast_data
)

if response.status_code == 201:
    print("All forecasts submitted successfully!")

Withdrawing Forecasts

You can withdraw your current forecast on a question:
import requests

API_TOKEN = "your_api_token_here"
headers = {"Authorization": f"Token {API_TOKEN}"}

# Withdraw forecast
withdrawal_data = [
    {"question": 1}
]

response = requests.post(
    "https://www.metaculus.com/api/questions/withdraw/",
    headers=headers,
    json=withdrawal_data
)

if response.status_code == 201:
    print("Forecast withdrawn successfully!")

Next Steps

Build docs developers (and LLMs) love