Skip to main content

Custom Emission Factors Guide

Custom emission factors allow you to use supplier-verified emission data instead of generic database factors, significantly improving the accuracy of your carbon accounting.
Use custom emission factors only when you have verified, supplier-specific data. Incorrect factors can significantly impact your footprint accuracy.

When to Use Custom Emission Factors

βœ… Use Custom Factors When:

Suppliers provide verified LCA data for their products.Example: Your aluminum supplier provides an EPD showing their recycled aluminum has 2.15 kg CO2e/kg instead of the generic 8.5 kg CO2e/kg.Accuracy improvement: Β±5-15% vs Β±30-50% with generic factors
You purchase renewable energy with specific grid mix documentation.Example: 100% wind energy PPA with zero emissions vs generic grid electricity at 0.38 kg CO2e/kWh.Accuracy improvement: Eliminates Scope 2 uncertainty
Your supplier uses unique processes that differ from industry averages.Example: Waste incineration with energy recovery has net lower emissions than standard incineration.Accuracy improvement: Β±10-20% vs Β±40-60%
Regulations require specific calculation methods or factors.Example: EU requires specific factors for certain industries under CBAM.Accuracy improvement: Compliance-grade accuracy

❌ Don’t Use Custom Factors When:

  • You’re estimating or guessing values (use standard factors instead)
  • Data is not from verified sources (EPDs, audited LCAs)
  • You want to artificially lower emissions (greenwashing)
  • Standard Dcycle factors are appropriate and available

Understanding the Structure

Custom emission factors are organized in a two-level hierarchy:
Custom Emission Group (Category)
β”œβ”€ Custom Emission Factor 1
β”œβ”€ Custom Emission Factor 2
└─ Custom Emission Factor 3

Custom Emission Groups

Groups organize related factors by category:
CategoryUse ForExample
purchasesSupplier-specific product factors”Supplier ABC Materials 2024”
wastesCustom waste treatment factors”Local Recycling Facility”
energyRenewable energy contracts”Wind Farm PPA 2024-2034”

Custom Emission Factors

Individual factors within a group with:
  • Emission values for each GHG (CO2, CH4, N2O, etc.)
  • Uncertainty grade (0-100%)
  • Validity period
  • Documentation reference
  • Category-specific fields (renewable %, hazardous, etc.)

Step-by-Step Implementation

Using the Dcycle App?You can also create custom emission factors through our web interface:

Step 1: Get Required Unit IDs

First, find the unit ID for your factor:
import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
    "x-user-id": os.getenv("DCYCLE_USER_ID")
}

# Get available units
units = requests.get(
    "https://api.dcycle.io/api/v1/units",
    headers=headers,
    params={"page": 1, "size": 100}
).json()

# Find kilogram unit
kg_unit = next(u for u in units['items'] if u['abbreviation'] == 'kg')
print(f"Kilogram unit ID: {kg_unit['id']}")

Step 2: Create a Custom Emission Group

Create a group to organize your factors:
# Create group for supplier materials
group_data = {
    "name": "Supplier ABC Materials 2024",
    "description": "EPD-verified emission factors from Supplier ABC. All factors third-party verified by Bureau Veritas. Valid for 2024.",
    "category": "purchases",  # purchases, wastes, or energy
    "ghg_type": 1  # 1=fossil, 2=biogenic, 3=mixed
}

group = requests.post(
    "https://api.dcycle.io/api/v1/custom_emission_groups",
    headers=headers,
    json=group_data
).json()

group_id = group['id']
print(f"βœ… Created group: {group_id}")

Step 3: Add Custom Emission Factors

Add individual factors to the group:
# Create custom factor for recycled aluminum
factor_data = {
    "ef_name": "Recycled Aluminum Sheet - Supplier ABC",
    "unit_id": kg_unit['id'],
    "factor_uploaded_by": "[email protected]",
    "tag": "advanced",  # "simple" or "advanced"
    "uncertainty_grade": 12,  # 0-100% (lower = more certain)
    "factor_start_date": "2024-01-01",
    "factor_end_date": "2024-12-31",
    "additional_docs": "EPD No. ABC-2024-001, Bureau Veritas verified, dated 2024-01-15. Cradle-to-gate LCA.",
    "emission_factor_values": [
        {"gas_type": "CO2", "value": 2.15},
        {"gas_type": "CH4", "value": 0.008},
        {"gas_type": "N2O", "value": 0.002}
    ],
    "recycled": True  # For material factors
}

factor = requests.post(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{group_id}",
    headers=headers,
    json=factor_data
).json()

factor_id = factor['id']
print(f"βœ… Created factor: {factor_id}")
print(f"   Total CO2e: {sum(v['value'] for v in factor['emission_factor_values'])} kg/kg")

Step 4: Use the Custom Factor

Reference the factor when tracking purchases:
# Track purchase using custom factor
purchase_data = {
    "name": "Aluminum sheets from Supplier ABC",
    "custom_emission_factor_id": factor_id,  # Use custom factor
    "quantity": 1000,
    "unit_id": kg_unit['id'],
    "purchase_date": "2024-03-15",
    "supplier_id": "supplier-abc-uuid"  # Optional
}

purchase = requests.post(
    "https://api.dcycle.io/api/v1/purchases",
    headers=headers,
    json=purchase_data
).json()

print(f"βœ… Purchase tracked")
print(f"   Quantity: {purchase['quantity']} kg")
print(f"   Emissions: {purchase['co2e']} kg CO2e")
print(f"   Used custom factor: {purchase['emission_factor_used']}")

Real-World Examples

Example 1: Supplier-Specific Product Portfolio

Track a complete product portfolio from a single supplier:
# Create group
group = requests.post(
    "https://api.dcycle.io/api/v1/custom_emission_groups",
    headers=headers,
    json={
        "name": "GreenTech Industries 2024",
        "description": "Complete product portfolio with verified EPDs. Updated quarterly.",
        "category": "purchases",
        "ghg_type": 1
    }
).json()

# Add multiple products
products = [
    {
        "ef_name": "Recycled Aluminum Sheet",
        "emission_factor_values": [
            {"gas_type": "CO2", "value": 2.15},
            {"gas_type": "CH4", "value": 0.008},
            {"gas_type": "N2O", "value": 0.002}
        ],
        "recycled": True,
        "uncertainty_grade": 12,
        "additional_docs": "EPD-GT-AL-2024"
    },
    {
        "ef_name": "Low-Carbon Steel Beam",
        "emission_factor_values": [
            {"gas_type": "CO2", "value": 1.85},
            {"gas_type": "CH4", "value": 0.005},
            {"gas_type": "N2O", "value": 0.001}
        ],
        "recycled": False,
        "uncertainty_grade": 18,
        "additional_docs": "EPD-GT-ST-2024"
    },
    {
        "ef_name": "Recycled Plastic Granules",
        "emission_factor_values": [
            {"gas_type": "CO2", "value": 1.45},
            {"gas_type": "CH4", "value": 0.012},
            {"gas_type": "N2O", "value": 0.003}
        ],
        "recycled": True,
        "uncertainty_grade": 20,
        "additional_docs": "EPD-GT-PL-2024"
    }
]

for product in products:
    product.update({
        "unit_id": kg_unit['id'],
        "factor_uploaded_by": "[email protected]",
        "tag": "advanced",
        "factor_start_date": "2024-01-01",
        "factor_end_date": "2024-12-31"
    })

    factor = requests.post(
        f"https://api.dcycle.io/api/v1/custom_emission_factors/{group['id']}",
        headers=headers,
        json=product
    ).json()

    print(f"βœ… Added: {factor['ef_name']}")

Example 2: Renewable Energy PPA

Track a Power Purchase Agreement for wind energy:
# Create energy group
ppa_group = requests.post(
    "https://api.dcycle.io/api/v1/custom_emission_groups",
    headers=headers,
    json={
        "name": "Wind Farm PPA 2024-2034",
        "description": "10-year wind energy PPA. Contract #PPA-WIND-2024-001. 100% renewable allocation.",
        "category": "energy",
        "ghg_type": 2  # Biogenic (renewable)
    }
).json()

# Get kWh unit
kwh_unit = next(u for u in units['items'] if u['abbreviation'] == 'kWh')

# Create zero-emission factor
ppa_factor = requests.post(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{ppa_group['id']}",
    headers=headers,
    json={
        "ef_name": "Wind Farm PPA - Northern Region",
        "unit_id": kwh_unit['id'],
        "factor_uploaded_by": "[email protected]",
        "tag": "advanced",
        "uncertainty_grade": 5,  # Very low (contract guaranteed)
        "factor_start_date": "2024-01-01",
        "factor_end_date": "2034-12-31",  # 10-year contract
        "additional_docs": "PPA Contract #PPA-WIND-2024-001, signed 2023-11-15",
        "emission_factor_values": [
            {"gas_type": "CO2", "value": 0.0}  # Zero direct emissions
        ],
        "renewable_percentage": 100.0
    }
).json()

print(f"βœ… PPA factor created: {ppa_factor['id']}")

Example 3: Waste Treatment Facility

Custom factors for a specific waste treatment facility:
# Create waste group
waste_group = requests.post(
    "https://api.dcycle.io/api/v1/custom_emission_groups",
    headers=headers,
    json={
        "name": "Regional Waste Facility 2024",
        "description": "Custom factors for local waste treatment with energy recovery. Facility report Q4 2023.",
        "category": "wastes",
        "ghg_type": 3  # Mixed (fossil + biogenic)
    }
).json()

# Incineration with energy recovery
waste_factor = requests.post(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{waste_group['id']}",
    headers=headers,
    json={
        "ef_name": "Mixed Waste Incineration with Energy Recovery",
        "unit_id": kg_unit['id'],
        "factor_uploaded_by": "[email protected]",
        "tag": "advanced",
        "uncertainty_grade": 25,
        "factor_start_date": "2024-01-01",
        "factor_end_date": "2024-12-31",
        "additional_docs": "Facility report Q4 2023. Includes energy credit allocation.",
        "emission_factor_values": [
            {"gas_type": "CO2", "value": 0.45},  # Net after energy recovery
            {"gas_type": "CH4", "value": 0.002},
            {"gas_type": "N2O", "value": 0.015}  # Higher from incineration
        ],
        "hazardous": False,
        "low_code": "19 12 10",  # LER code for combustible waste
        "rd_code": "R1"  # Recovery operation with energy
    }
).json()

print(f"βœ… Waste factor created")

Data Quality and Uncertainty

Uncertainty Grades

Track confidence in your data:
GradeConfidenceWhen to Use
0-20%Very HighSupplier-verified EPD, third-party audited
21-40%HighIndustry-specific studies, peer-reviewed
41-60%MediumReasonable estimates, documented assumptions
61-80%LowLimited data, significant assumptions
81-100%Very LowRough estimates (improve ASAP)
# Example: Track uncertainty over time
factors_by_uncertainty = {
    "high_confidence": [],  # < 20%
    "medium_confidence": [],  # 20-50%
    "low_confidence": []  # > 50%
}

for factor in all_factors:
    ug = factor.get('uncertainty_grade', 100)

    if ug < 20:
        factors_by_uncertainty['high_confidence'].append(factor)
    elif ug < 50:
        factors_by_uncertainty['medium_confidence'].append(factor)
    else:
        factors_by_uncertainty['low_confidence'].append(factor)

# Prioritize improving low confidence factors
print(f"Improve these {len(factors_by_uncertainty['low_confidence'])} factors:")
for factor in factors_by_uncertainty['low_confidence']:
    print(f"  - {factor['ef_name']}: {factor['uncertainty_grade']}%")

Documentation Best Practices

Always document your sources:
# βœ… Good documentation
"additional_docs": """
EPD No. ABC-2024-001
Third-party verified: Bureau Veritas
Verification date: 2024-01-15
System boundary: Cradle-to-gate
Methodology: ISO 14040/14044
Functional unit: 1 kg of product
Allocation: Economic allocation
Data quality: Primary data from production 2023
Geographic scope: European production
"""

# ❌ Poor documentation
"additional_docs": "supplier data"

Managing Custom Factors

List All Factors in a Group

group_id = "group-uuid"

factors = requests.get(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/list/{group_id}",
    headers=headers,
    params={"page": 1, "size": 50}
).json()

print(f"Group has {factors['total']} factors:")
for factor in factors['items']:
    total_co2e = sum(v['value'] for v in factor['emission_factor_values'])
    print(f"  - {factor['ef_name']}: {total_co2e} kg CO2e/{factor['unit_id']}")

Update a Factor

# Get current factor
factor = requests.get(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{factor_id}",
    headers=headers
).json()

# Update with new EPD data
update_data = {
    "factor_uploaded_by": "[email protected]",
    "emission_factor_values": [
        {"gas_type": "CO2", "value": 2.05},  # Updated value
        {"gas_type": "CH4", "value": 0.007},
        {"gas_type": "N2O", "value": 0.002}
    ],
    "additional_docs": f"{factor['additional_docs']} | Updated 2024-06-15 with Q2 2024 EPD"
}

updated = requests.patch(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{factor_id}",
    headers=headers,
    json=update_data
).json()

print(f"βœ… Factor updated")

Archive Old Factors

Instead of deleting, mark as outdated:
# Delete old factor
requests.delete(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{old_factor_id}",
    headers=headers
)

# Create new factor with updated data
new_factor = requests.post(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{group_id}",
    headers=headers,
    json={
        **new_factor_data,
        "ef_name": "Product XYZ - Supplier ABC (2024 Update)",
        "additional_docs": "Supersedes factor-old-uuid. Updated Q2 2024."
    }
).json()

Validation and Quality Checks

Validate Before Creating

def validate_custom_factor(data):
    """Validate custom factor data"""

    # Required fields
    assert data.get('ef_name'), "Name required"
    assert data.get('unit_id'), "Unit required"
    assert data.get('emission_factor_values'), "Emission values required"

    # Check CO2 is present
    gases = [v['gas_type'] for v in data['emission_factor_values']]
    assert 'CO2' in gases or 'co2e' in gases, "CO2 or co2e required"

    # Check tag matches emission values
    if data.get('tag') == 'advanced':
        assert len(data['emission_factor_values']) >= 3, "Advanced tag requires 3+ gases"

    # Uncertainty check
    if data.get('uncertainty_grade', 0) > 50:
        print(f"⚠️  Warning: High uncertainty ({data['uncertainty_grade']}%)")

    # Documentation check
    if not data.get('additional_docs'):
        print(f"⚠️  Warning: No documentation provided")

    return True

Compare with Standard Factors

# Calculate difference from standard factor
custom_co2e = sum(v['value'] for v in custom_factor['emission_factor_values'])
standard_co2e = 8.5  # Generic aluminum factor

difference_pct = ((custom_co2e - standard_co2e) / standard_co2e) * 100

print(f"Custom factor: {custom_co2e} kg CO2e/kg")
print(f"Standard factor: {standard_co2e} kg CO2e/kg")
print(f"Difference: {difference_pct:+.1f}%")

if abs(difference_pct) > 50:
    print("⚠️  Warning: >50% difference from standard. Verify data.")

Troubleshooting

Issue: Factor Not Applied

# Check if factor exists and is valid
factor = requests.get(
    f"https://api.dcycle.io/api/v1/custom_emission_factors/{factor_id}",
    headers=headers
).json()

# Check dates
from datetime import date
today = date.today()
start = date.fromisoformat(factor['factor_start_date'])
end = date.fromisoformat(factor['factor_end_date'])

if not (start <= today <= end):
    print(f"❌ Factor not valid today ({today})")
    print(f"   Valid: {start} to {end}")

Issue: Validation Error on Creation

# Common errors:

# 1. Missing CO2 value
"emission_factor_values": [
    {"gas_type": "CH4", "value": 0.008}  # ❌ Missing CO2
]

# 2. Wrong tag
"tag": "simple",
"emission_factor_values": [
    {"gas_type": "CO2", "value": 2.15},
    {"gas_type": "CH4", "value": 0.008}  # ❌ Simple needs only co2e
]

# 3. Invalid uncertainty grade
"uncertainty_grade": 150  # ❌ Must be 0-100

Next Steps