<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: sustainmetrics.net</title>
    <description>The latest articles on DEV Community by sustainmetrics.net (@sustainmnet).</description>
    <link>https://dev.to/sustainmnet</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3887258%2F64920b2f-cfac-41d3-be27-5316f8757275.jpg</url>
      <title>DEV Community: sustainmetrics.net</title>
      <link>https://dev.to/sustainmnet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sustainmnet"/>
    <language>en</language>
    <item>
      <title>I parsed 18,000 emission factors from DEFRA, EPA, and ADEME into one free API</title>
      <dc:creator>sustainmetrics.net</dc:creator>
      <pubDate>Sun, 19 Apr 2026 11:07:49 +0000</pubDate>
      <link>https://dev.to/sustainmnet/i-parsed-18000-emission-factors-from-defra-epa-and-ademe-into-one-free-api-347d</link>
      <guid>https://dev.to/sustainmnet/i-parsed-18000-emission-factors-from-defra-epa-and-ademe-into-one-free-api-347d</guid>
      <description>&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;I needed emission factors for a carbon reporting project.&lt;/p&gt;

&lt;p&gt;If you've tried this, you know what happens next: you open the &lt;a href="https://www.gov.uk/government/publications/greenhouse-gas-reporting-conversion-factors-2025" rel="noopener noreferrer"&gt;DEFRA 2025 flat-format spreadsheet&lt;/a&gt; and it's 3,997 rows across 40-something sheets, with the same activity described three different ways. You download the &lt;a href="https://www.epa.gov/climateleadership/ghg-emission-factors-hub" rel="noopener noreferrer"&gt;EPA Hub workbook&lt;/a&gt; and it's 12 separate tables, mixed units (&lt;code&gt;kg/MMBtu&lt;/code&gt;, &lt;code&gt;g/MMBtu&lt;/code&gt;, &lt;code&gt;lb/MWh&lt;/code&gt;), and different GWP conventions depending on year. You grab the &lt;a href="https://base-carbone.ademe.fr/" rel="noopener noreferrer"&gt;ADEME Base Carbone&lt;/a&gt; CSV — 11,000 rows in &lt;strong&gt;French&lt;/strong&gt;, with semicolon delimiters, Windows-1252 encoding, and commas as decimal separators.&lt;/p&gt;

&lt;p&gt;Three weeks into the project I realised I wasn't building a carbon calculator. I was building a parser pipeline.&lt;/p&gt;

&lt;p&gt;This post is what I wish I'd read on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The units that lie
&lt;/h2&gt;

&lt;p&gt;EPA's CH₄ and N₂O factors look like they're in kg/MMBtu, same as CO₂. They're not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EPA natural gas (stationary combustion):
  CO₂ = 53.06 kg/MMBtu
  CH₄ = 1.0 g/MMBtu    ← grams, not kg
  N₂O = 0.1 g/MMBtu    ← grams, not kg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you forget the unit mismatch, your CH₄ footprint is off by a factor of 1,000. Which is funny because CH₄ has a GWP of 28, so the total error ends up being &lt;strong&gt;a factor of 28,000 too low&lt;/strong&gt; on the methane portion.&lt;/p&gt;

&lt;p&gt;The fix is trivial once you know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;co2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;qty_mmbtu&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;co2_factor_mmbtu&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                    &lt;span class="c1"&gt;// already kg&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ch4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;qty_mmbtu&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;ch4_factor_mmbtu&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;GWP_CH4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// g → kg CO₂e&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n2o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;qty_mmbtu&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;n2o_factor_mmbtu&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;GWP_N2O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// g → kg CO₂e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EPA's electricity factors (eGRID) are in &lt;code&gt;lb/MWh&lt;/code&gt;. You multiply by 0.453592 to get kilograms. EPA's waste factors are in &lt;code&gt;metric tons CO₂e per short ton material&lt;/code&gt;, which requires a &lt;code&gt;×1000&lt;/code&gt; to get to kg. Every source has its own version of this trap.&lt;/p&gt;

&lt;p&gt;DEFRA is kinder — almost every factor is already in &lt;code&gt;kg CO₂e / activity unit&lt;/code&gt;. When you see something like this, keep it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GWP versions that don't match
&lt;/h2&gt;

&lt;p&gt;Global Warming Potential values change as IPCC publishes new assessment reports. For 100-year horizons:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gas&lt;/th&gt;
&lt;th&gt;AR4&lt;/th&gt;
&lt;th&gt;AR5&lt;/th&gt;
&lt;th&gt;AR6&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CH₄&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;28&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;27.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N₂O&lt;/td&gt;
&lt;td&gt;298&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;265&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;273&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The GHG Protocol default is AR5. EPA 2023 factors were still on AR4 (CH₄=25). EPA 2024+ moved to AR5 (CH₄=28). DEFRA has been on AR5 since 2020.&lt;/p&gt;

&lt;p&gt;If your calculator silently uses a single GWP table, you're either inflating 2023 methane or deflating 2024 methane. I keep a per-year &lt;code&gt;GWP&lt;/code&gt; object and pull the matching one when calculating.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope 2 has two answers
&lt;/h2&gt;

&lt;p&gt;GHG Protocol Scope 2 Guidance (2015) requires &lt;strong&gt;dual reporting&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Location-based:&lt;/strong&gt; grid average emission factor (e.g. DEFRA UK electricity: 0.177 kg CO₂e/kWh in 2025)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Market-based:&lt;/strong&gt; contractually-driven. Backed by REC / I-REC / GO / PPA certificates → often zero or very low.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't interchangeable. A company with 100% renewable PPA can legitimately report 0 for Scope 2 market-based and 3,200 kg CO₂e for the same activity location-based. Every credible framework (CDP, SBTi, EU CSRD) wants both.&lt;/p&gt;

&lt;p&gt;I show both by default on every electricity entry. The REC toggle zeroes out the market-based side.&lt;/p&gt;

&lt;h2&gt;
  
  
  T&amp;amp;D losses are Scope 3, not Scope 2
&lt;/h2&gt;

&lt;p&gt;This one surprised me.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GHG Protocol Scope 3 Standard, Category 3 (Fuel- and Energy-Related Activities)&lt;/strong&gt;:&lt;br&gt;
Transmission &amp;amp; distribution losses for purchased electricity are Scope 3.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you pull the standard DEFRA UK electricity factor (0.177 in 2025), &lt;strong&gt;it doesn't include T&amp;amp;D&lt;/strong&gt;. There's a separate T&amp;amp;D factor (&lt;code&gt;0.01853 kg CO₂e/kWh&lt;/code&gt; for UK) that DEFRA labels &lt;code&gt;"scope": "Scope 3"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Plenty of calculators fold T&amp;amp;D into Scope 2. That's wrong under GHG Protocol, DEFRA guidance, EPA, and ISO 14064-1. I added an auto-suggest banner: if a user adds UK DEFRA electricity to their inventory, we prompt them to also add the matching Scope 3 T&amp;amp;D entry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it in an API
&lt;/h2&gt;

&lt;p&gt;After three weeks of parsing, I had a single normalized index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEFRA 2023-2025: 3,997 factors
EPA 2023-2025:   1,260 factors
ADEME 2024:     11,442 factors
Ember 2024:        193 factors (193 countries grid intensity)
------
Total: ~17,000 distinct activity-factor records
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every record carries its source, year, scope, license, and original unit.&lt;/p&gt;

&lt;p&gt;The REST API is live at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://www.sustainmetrics.net/api/v1/factors?source=defra&amp;amp;year=2025&amp;amp;category=fuels"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-Key: sm_your_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response (trimmed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"defra"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Scope 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuels"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"activity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Natural gas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kWh (Net CV)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"co2e_factor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.18290&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Open Government Licence v3.0"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Free tier is 50 calls/day; signup just needs an email. Calculator itself needs no signup at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I went wrong
&lt;/h2&gt;

&lt;p&gt;A few things I had to rewrite:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First pass used a single GWP table.&lt;/strong&gt; Had to redo it once I saw EPA 2023 vs 2024 diverge. Lesson: version your GWP as data, not as a constant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treated DEFRA's &lt;code&gt;scope&lt;/code&gt; field as string.&lt;/strong&gt; It's sometimes a multi-line string with embedded newlines. Normalize before querying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Didn't handle ADEME's French decimal commas.&lt;/strong&gt; Parsed numbers came out zero. Added a &lt;code&gt;.replace(',', '.')&lt;/code&gt; pass before &lt;code&gt;parseFloat&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stored cloud projects as JSON blobs without a schema.&lt;/strong&gt; When I wanted to run cross-project trend analysis, I couldn't query them efficiently. Now the blob has a minimum required schema and indexed fields for year, scope totals, source.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I'd like feedback on
&lt;/h2&gt;

&lt;p&gt;If you've built similar tooling or you do carbon accounting for real:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The cross-source comparison page&lt;/strong&gt; at &lt;a href="https://www.sustainmetrics.net/compare" rel="noopener noreferrer"&gt;sustainmetrics.net/compare&lt;/a&gt; shows factor differences for the same activity across standards. Does it surface anything useful to you?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API shape&lt;/strong&gt; — &lt;code&gt;/api/v1/factors?source=defra&amp;amp;year=2025&amp;amp;scope=Scope%202&amp;amp;search=electricity&lt;/code&gt;. Is this the shape you'd want, or would you prefer versioned JSON Schema + cursor-based pagination?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any obvious scope/unit/GWP mistakes&lt;/strong&gt; in the index. I did the parsing mostly by hand from official flat files. Second pair of eyes very welcome.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The calculator is free, the comparison page is free, and 50 API calls a day is free (email signup only). Pro ($29/mo) exists for people who need PDF/Excel exports and cloud project storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Live site: &lt;a href="https://www.sustainmetrics.net" rel="noopener noreferrer"&gt;https://www.sustainmetrics.net&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;30-second product tour: &lt;a href="https://www.sustainmetrics.net/intro" rel="noopener noreferrer"&gt;https://www.sustainmetrics.net/intro&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;API docs: &lt;a href="https://www.sustainmetrics.net/docs" rel="noopener noreferrer"&gt;https://www.sustainmetrics.net/docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Methodology: &lt;a href="https://www.sustainmetrics.net/methodology" rel="noopener noreferrer"&gt;https://www.sustainmetrics.net/methodology&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Compare standards: &lt;a href="https://www.sustainmetrics.net/compare" rel="noopener noreferrer"&gt;https://www.sustainmetrics.net/compare&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of this is wrong or could be better, tell me.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>api</category>
      <category>sustainability</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
