<?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: Data Factory</title>
    <description>The latest articles on DEV Community by Data Factory (@data_factory_nerd).</description>
    <link>https://dev.to/data_factory_nerd</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4241961%2F8ee76f30-a237-4161-8ddf-05c8c86d8d99.png</url>
      <title>DEV Community: Data Factory</title>
      <link>https://dev.to/data_factory_nerd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/data_factory_nerd"/>
    <language>en</language>
    <item>
      <title>Track new SAM.gov contract opportunities with Python (no SAM.gov API key)</title>
      <dc:creator>Data Factory</dc:creator>
      <pubDate>Fri, 13 Nov 2026 00:41:17 +0000</pubDate>
      <link>https://dev.to/data_factory_nerd/track-new-samgov-contract-opportunities-with-python-no-samgov-api-key-4gnm</link>
      <guid>https://dev.to/data_factory_nerd/track-new-samgov-contract-opportunities-with-python-no-samgov-api-key-4gnm</guid>
      <description>&lt;p&gt;If you sell to the US federal government, SAM.gov is where the work is posted: solicitations, sources-sought notices, presolicitations and award notices from every agency. The website is fine for browsing, but most teams want something else: &lt;strong&gt;a list of open bids that match what they do, in a spreadsheet or CRM, refreshed every morning, with only the new ones flagged.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This tutorial shows how to get there in about 30 lines of Python, using a hosted scraper on Apify (&lt;a href="https://apify.com/data_factory_nerd/sam-gov-contract-opportunities" rel="noopener noreferrer"&gt;SAM.gov Contract Opportunities Scraper&lt;/a&gt;). You don't need a SAM.gov account or API key. You need an Apify account and its API token.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we're building
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A one-off export: open IT-services opportunities (NAICS 541511/541512/541519) into &lt;code&gt;sam_bids.csv&lt;/code&gt;, sorted by response deadline, with a direct link to the first attachment (usually the SOW or RFP).&lt;/li&gt;
&lt;li&gt;Narrower searches by &lt;strong&gt;PSC code&lt;/strong&gt; and &lt;strong&gt;agency&lt;/strong&gt; (e.g. janitorial work for the Forest Service).&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;daily alert&lt;/strong&gt; that returns only notices you haven't seen yet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Get your API token
&lt;/h2&gt;

&lt;p&gt;Sign in to Apify, open &lt;strong&gt;Settings → API &amp;amp; Integrations&lt;/strong&gt;, and copy your API token. Put it in an environment variable rather than in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="kd"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;APIFY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...   &lt;span class="c"&gt;# your token&lt;/span&gt;
pip install requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Export open bids to CSV
&lt;/h2&gt;

&lt;p&gt;The Apify API has an endpoint that runs an Actor, waits for it, and returns the results in one request: &lt;code&gt;run-sync-get-dataset-items&lt;/code&gt;. (It's meant for short runs. Apify's docs say runs longer than 300 seconds return HTTP 408, so keep &lt;code&gt;maxItems&lt;/code&gt; modest or use the async API for big pulls.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="no"&gt;ACTOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"data_factory_nerd~sam-gov-contract-opportunities"&lt;/span&gt;
&lt;span class="no"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"https://api.apify.com/v2/acts/{ACTOR}/run-sync-get-dataset-items"&lt;/span&gt;

&lt;span class="n"&gt;run_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"naicsCodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"541511"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"541512"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"541519"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# IT services&lt;/span&gt;
    &lt;span class="s2"&gt;"noticeTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"o"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"k"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;# solicitations, combined, presolicitations, sources sought&lt;/span&gt;
    &lt;span class="s2"&gt;"openForResponseOnly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                   &lt;span class="c1"&gt;# skip notices whose deadline has passed&lt;/span&gt;
    &lt;span class="s2"&gt;"includeAttachments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                    &lt;span class="c1"&gt;# direct links to the SOW / RFP documents&lt;/span&gt;
    &lt;span class="s2"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="no"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Bearer {os.environ['APIFY_TOKEN']}"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;notices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"sam_bids.csv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"deadline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"agency"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"naics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"set_aside"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"first_attachment"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"responseDeadline"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="s2"&gt;"9999"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;att&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"attachments"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"responseDeadline"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"subTier"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"department"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"naicsCode"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"setAside"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;att&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Saved {len(notices)} open opportunities to sam_bids.csv"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I ran it (Nov 12, 2026, ~5 PM ET) it took about 20 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Saved 48 open opportunities to sam_bids.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first rows looked like this (trimmed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deadline,title,agency,naics,...
2026-11-13T17:00:00+00:00,W50NH9-27-R-A006 ... Scalable GEOINT ...,DEPT OF THE ARMY,541519,...
2026-11-13T20:00:00+00:00,Enterprise Next (ENX) Draft RFP,NATIONAL AERONAUTICS AND SPACE ADMINISTRATION,541512,...
2026-11-13T20:00:00+00:00,Request for Information: Air Operations Center (AOC) ...,DEPT OF THE AIR FORCE,541512,...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth knowing about the data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dates are UTC ISO 8601&lt;/strong&gt;, so sorting by deadline is a plain string sort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;department&lt;/code&gt; / &lt;code&gt;subTier&lt;/code&gt; / &lt;code&gt;office&lt;/code&gt;&lt;/strong&gt; give the full agency path. When a search hit doesn't include it, the scraper looks it up in SAM.gov's federal hierarchy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;contacts&lt;/code&gt;&lt;/strong&gt; lists the official points of contact (name, email, phone) from the notice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;attachments&lt;/code&gt;&lt;/strong&gt; holds &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;sizeBytes&lt;/code&gt; and &lt;code&gt;postedDate&lt;/code&gt;. For files, the URL is a sam.gov download link that redirects to the document. Some notices point to external systems instead (for example DoD's PIEE). Those come through as &lt;code&gt;type: "link"&lt;/code&gt; with the external URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Need Excel instead? The same endpoint accepts &lt;code&gt;format=xlsx&lt;/code&gt; or &lt;code&gt;format=csv&lt;/code&gt; as a query parameter, so you can skip the CSV code entirely.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. Narrow it down: PSC codes and agencies
&lt;/h2&gt;

&lt;p&gt;NAICS describes the industry. &lt;strong&gt;PSC (Product Service Code)&lt;/strong&gt; describes what is being bought, and it's often the sharper filter. Combine it with an agency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;run_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"pscCodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"S201"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;# custodial / janitorial services&lt;/span&gt;
    &lt;span class="s2"&gt;"agencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"FOREST SERVICE"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# name, acronym (GSA, DOD) or numeric org ID&lt;/span&gt;
    &lt;span class="s2"&gt;"openForResponseOnly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"includeAttachments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The run log shows how each agency was matched, so you can confirm you got the right organization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agency 'FOREST SERVICE' -&amp;gt; FOREST SERVICE (org ID 100013241)
query='*': 10 matching notices on SAM.gov
Done: 6 SAM.gov notices saved
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Names that can't be matched are skipped with a warning, not silently ignored. Acronyms like &lt;code&gt;DOD&lt;/code&gt; or &lt;code&gt;GSA&lt;/code&gt; and short names like &lt;code&gt;navy&lt;/code&gt; resolve to the official hierarchy entries (&lt;code&gt;DEPT OF DEFENSE&lt;/code&gt;, &lt;code&gt;GENERAL SERVICES ADMINISTRATION&lt;/code&gt;, &lt;code&gt;DEPT OF THE NAVY&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Daily alerts: only new notices
&lt;/h2&gt;

&lt;p&gt;Re-running the same search every day gives you the same notices again. Turn on &lt;strong&gt;monitor mode&lt;/strong&gt; instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;run_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"naicsCodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"541511"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"541512"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"541519"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"noticeTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"o"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"k"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"openForResponseOnly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"onlyNew"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# return only notices not returned by a previous run of this search&lt;/span&gt;
    &lt;span class="s2"&gt;"maxItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first run returns everything that matches and remembers the notice IDs.&lt;/li&gt;
&lt;li&gt;Later runs return &lt;strong&gt;only notices that weren't returned before&lt;/strong&gt;. If nothing new was posted, you get an empty dataset, and with pay-per-result pricing an empty run produces no result charges.&lt;/li&gt;
&lt;li&gt;The memory lives in a named key-value store in &lt;em&gt;your&lt;/em&gt; Apify account (&lt;code&gt;data-factory-samgov-monitor&lt;/code&gt;), one record per search. Change the filters and you get a fresh history. To keep one history while you tweak filters, set &lt;code&gt;"monitorKey": "it-bids"&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To verify it, I ran the PSC + agency search above twice in a row. The first run returned 6 notices. The second returned 0 and logged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Monitor mode: 6 items already seen for this search (...). Only new items will be returned.
Done: 0 new SAM.gov notices saved
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Put it on a schedule
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In Apify Console, open the Actor, enter the input above, and save it as a &lt;strong&gt;task&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Schedules → Create new&lt;/strong&gt;, add the task, and pick a cron expression such as &lt;code&gt;0 8 * * *&lt;/code&gt; (every day at 8 AM; schedules support time zones).&lt;/li&gt;
&lt;li&gt;Add an integration or webhook to the task (Slack, email, Google Sheets, Zapier, Make) so each morning's new notices land where your capture team works.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you'd rather keep it in code, run the snippet from step 2 with &lt;code&gt;"onlyNew": True&lt;/code&gt; from your own cron job. The memory lives on the Apify side, so it works from any machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;The scraper charges per result: &lt;strong&gt;$3.00 per 1,000 notices&lt;/strong&gt; at the time of writing (see the Store page for the current price). A daily monitor that finds 20 new notices costs about 6 cents per day. You can cap spend on any run with the &lt;code&gt;maxTotalChargeUsd&lt;/code&gt; query parameter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notice type codes cheat sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;o&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Solicitation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;k&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Combined Synopsis/Solicitation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Presolicitation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sources Sought&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Special Notice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Award Notice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Justification (J&amp;amp;A)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Intent to Bundle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sale of Surplus Property&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;You now have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a CSV of open bids with deadlines, agencies and document links,&lt;/li&gt;
&lt;li&gt;PSC and agency filters for targeted searches, and&lt;/li&gt;
&lt;li&gt;a daily "only new" feed that costs nothing on days with nothing new.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The scraper is on the Apify Store: &lt;a href="https://apify.com/data_factory_nerd/sam-gov-contract-opportunities" rel="noopener noreferrer"&gt;SAM.gov Contract Opportunities Scraper&lt;/a&gt;. Missing a field or filter? Open an issue on its &lt;strong&gt;Issues&lt;/strong&gt; tab.&lt;/p&gt;




&lt;p&gt;The full script is on GitHub: &lt;a href="https://github.com/data-factory-nerd/examples" rel="noopener noreferrer"&gt;data-factory-nerd/examples&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>govtech</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
