<?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: Manu Shukla</title>
    <description>The latest articles on DEV Community by Manu Shukla (@mr_manushukla).</description>
    <link>https://dev.to/mr_manushukla</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%2F4030821%2Fc19a9586-862e-4358-aeb1-c63dc32f3914.jpg</url>
      <title>DEV Community: Manu Shukla</title>
      <link>https://dev.to/mr_manushukla</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mr_manushukla"/>
    <language>en</language>
    <item>
      <title>Android developer verification: 30 September 2026 enforcement in 4 markets, and a six-week remediation plan</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 13:12:30 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/android-developer-verification-30-september-2026-enforcement-in-4-markets-and-a-six-week-4m0f</link>
      <guid>https://dev.to/mr_manushukla/android-developer-verification-30-september-2026-enforcement-in-4-markets-and-a-six-week-4m0f</guid>
      <description>&lt;h1&gt;
  
  
  Android developer verification: 30 September 2026 enforcement in 4 markets, and a six-week remediation plan
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; Android developer verification starts being enforced on 30 September 2026 for users in Brazil, Indonesia, Singapore and Thailand, across 7 participating app stores, on all certified Android devices running Android 7 or higher. Google's Android Developers Blog post of 18 June 2026 lists the stores: Google Play, HONOR App Market, OPPO App Market, Galaxy Store, Palm Store, V-Appstore and GetApps. Two dates matter more than the headline one. A D-U-N-S number, required to register as an organisation, can take up to 28 days to issue, so an Indian company starting the paperwork in late August is already tight. And a 15 July 2026 update to the same post warns Play developers that apps left unregistered by 30 September 2026 face removal from Google Play globally, not only in the four launch markets. Registration through the Android Developer Console costs a one-time $25 for a Full Distribution account, about ₹2,400 at the US$1 = INR 95.26 reference rate India Briefing used in May 2026, and is waived for Limited Distribution accounts.&lt;/p&gt;

&lt;p&gt;"This rollout is an industry-wide effort to create a safer ecosystem," wrote Matthew Forsythe, Director Product Management, Android App Safety at Google, in the announcement. For an Indian studio with apps in Jakarta, Bangkok, Singapore or Sao Paulo, that industry-wide framing has a practical translation: the same registration record now has to satisfy seven different stores at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually changes on 30 September
&lt;/h2&gt;

&lt;p&gt;From that date, the seven stores below will verify app installations in the four launch markets. Apps whose developers have not registered are blocked from installing by users on certified Android devices in the applicable regions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Store&lt;/th&gt;
&lt;th&gt;Operator&lt;/th&gt;
&lt;th&gt;Why it matters for Indian publishers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Google Play&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Primary channel; unregistered Play apps risk global removal, not just regional blocking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Galaxy Store&lt;/td&gt;
&lt;td&gt;Samsung&lt;/td&gt;
&lt;td&gt;Preinstalled on Samsung devices, so it is rarely the channel you opted into&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GetApps&lt;/td&gt;
&lt;td&gt;Xiaomi&lt;/td&gt;
&lt;td&gt;Ships on Xiaomi hardware; check whether your APK reaches users through it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OPPO App Market&lt;/td&gt;
&lt;td&gt;OPlus&lt;/td&gt;
&lt;td&gt;Operated by OPlus; in scope for all four launch markets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V-Appstore&lt;/td&gt;
&lt;td&gt;vivo&lt;/td&gt;
&lt;td&gt;In scope alongside OPPO; the two often ship on sibling hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HONOR App Market&lt;/td&gt;
&lt;td&gt;Honor&lt;/td&gt;
&lt;td&gt;In scope; a separate registration surface from Play&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Palm Store&lt;/td&gt;
&lt;td&gt;Transsion&lt;/td&gt;
&lt;td&gt;Reaches entry-tier Transsion devices; easy to overlook in a Play-first plan&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three scope limits are worth knowing before anyone panics. Enforcement in this phase applies only to those stores; if you distribute through a store not on the list, or users sideload your app directly, the requirement does not apply yet. For distribution outside Google Play, enforcement in the selected regions covers mobile and tablet form factors only, though Google recommends registering everything to future-proof availability. And if you distribute on Google Play at all, your apps across all form factors must be registered, which is the sentence most teams skim past.&lt;/p&gt;

&lt;p&gt;Devices in sanctioned countries are excluded from verification checks. Apps distributed through an organisation's own store to managed devices do not need to complete verification, because the IT admin has vetted them, though Google still recommends registering them so installs stay smooth if the app ever arrives from another source.&lt;/p&gt;

&lt;p&gt;Global expansion follows in 2027. Treat the September date as the dress rehearsal, not the deadline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five things that actually delay teams
&lt;/h2&gt;

&lt;p&gt;Most of this process is a form. The delays come from five specific places, and four of them are outside your engineering team's control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The D-U-N-S number.&lt;/strong&gt; Registering as an organisation requires a D-U-N-S number, the nine-digit business identifier from Dun &amp;amp; Bradstreet. It is free, and Google's FAQ states the process can take up to 28 days. Count backwards from 30 September and the safe start date was early September at the latest. If your Indian entity does not already have one from an Apple Developer Program enrolment, this is the long pole and it belongs to finance or company secretarial, not to the mobile team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signing key custody.&lt;/strong&gt; If you use Play App Signing, Google already has what it needs and your eligible apps are part of the automatic registration process. If you hold your own keys, someone has to produce them. Google's FAQ is blunt about the failure case: lose your signing key and you cannot register your packages. There is no recovery path. For studios that inherited apps from a previous vendor, or that shipped an app in 2019 and have not touched the keystore since, this is where the week disappears.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Package name collisions.&lt;/strong&gt; If a package name is already in use, you may be told your key is not eligible to claim it. Google's guidance is to consider a different package name. You can request registration of a contested name, but it goes to additional review and that package name may also be used by other developers. Changing a live app's package name is not a rename; it is a new listing, a lost install base and a new set of deep links. Check every package you own now, while changing one is still cheap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The forgotten apps.&lt;/strong&gt; Over 99% of apps on Play have been registered automatically, which is exactly why the remaining fraction is dangerous: nobody is looking for it. The white-label build for one enterprise client, the regional variant, the app a marketing team shipped in 2021 under a different account. These are the ones that trip the global removal warning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multiple accounts.&lt;/strong&gt; Studios that ship for clients often have apps scattered across several Play Console accounts, some owned by the client. Registration status is per account. There is no single dashboard across accounts, so the inventory has to be assembled by hand, once, and then kept.&lt;/p&gt;

&lt;h2&gt;
  
  
  A six-week remediation plan
&lt;/h2&gt;

&lt;p&gt;Six weeks is the realistic window if the D-U-N-S number is already in hand. If it is not, start that in week one and run the rest in parallel.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Week&lt;/th&gt;
&lt;th&gt;What to do&lt;/th&gt;
&lt;th&gt;What breaks if you skip it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Start the D-U-N-S application if you do not have one; list every Play Console and Android Developer Console account your organisation or clients control&lt;/td&gt;
&lt;td&gt;Up to 28 days of dead time later, with no way to compress it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Build the package inventory: every package name you ship, its store, its signing key location and its owner&lt;/td&gt;
&lt;td&gt;Forgotten apps stay forgotten until they are removed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Confirm signing key custody for every package not on Play App Signing; retrieve keystores from vendors and archive them properly&lt;/td&gt;
&lt;td&gt;A package you cannot sign is a package you cannot register, permanently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Register through Play Console for Play apps and the Android Developer Console for everything else; resolve any package-name conflicts&lt;/td&gt;
&lt;td&gt;Contested names go to review, which you cannot schedule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Wire the Android Developer ID Status API into CI so every build checks its own registration state&lt;/td&gt;
&lt;td&gt;The next new package ships unregistered and nobody notices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Verify status in all three surfaces, then re-check the four launch markets against your store list&lt;/td&gt;
&lt;td&gt;You find out on 1 October, from a support ticket&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The week five step is the one that separates a fix from a process. Google is shipping two APIs for this. The Android Developer ID Status API checks package name eligibility and registration status. The Android Developer Console API provides programmatic access for registering package names and managing keys. Both support OAuth delegation, so third-party platforms such as app stores can perform these operations on your behalf. Google said the Status API launches globally in July 2026 with early access for the Console API, and that both go global in August 2026.&lt;/p&gt;

&lt;p&gt;A build that cannot assert its own registration status is a build that will eventually ship unregistered. Put the check in the pipeline, fail the build on a negative, and the problem stops being seasonal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which registration path applies to you
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your situation&lt;/th&gt;
&lt;th&gt;Where to register&lt;/th&gt;
&lt;th&gt;Fee&lt;/th&gt;
&lt;th&gt;Government ID&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Play developer using Play App Signing&lt;/td&gt;
&lt;td&gt;Play Console, mostly automatic&lt;/td&gt;
&lt;td&gt;Existing Play account&lt;/td&gt;
&lt;td&gt;Already provided&lt;/td&gt;
&lt;td&gt;Eligible apps are auto-registered; still check Play Console Home&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Play developer holding own signing keys&lt;/td&gt;
&lt;td&gt;Play Console&lt;/td&gt;
&lt;td&gt;Existing Play account&lt;/td&gt;
&lt;td&gt;Already provided&lt;/td&gt;
&lt;td&gt;You must produce the key to claim the package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Play developer also shipping outside Play&lt;/td&gt;
&lt;td&gt;Play Console, single place for both&lt;/td&gt;
&lt;td&gt;Existing Play account&lt;/td&gt;
&lt;td&gt;Already provided&lt;/td&gt;
&lt;td&gt;Google's stated simplification; use one console, not two&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Organisation distributing only outside Play&lt;/td&gt;
&lt;td&gt;Android Developer Console, Full Distribution&lt;/td&gt;
&lt;td&gt;$25 one-time&lt;/td&gt;
&lt;td&gt;Yes, plus D-U-N-S number&lt;/td&gt;
&lt;td&gt;The D-U-N-S lead time is the constraint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Individual distributing only outside Play&lt;/td&gt;
&lt;td&gt;Android Developer Console, Full Distribution&lt;/td&gt;
&lt;td&gt;$25 one-time&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Fee described as similar to Play's $25 registration fee&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Student, teacher or hobbyist&lt;/td&gt;
&lt;td&gt;Android Developer Console, Limited Distribution&lt;/td&gt;
&lt;td&gt;Waived&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Up to 20 devices; scheduled to launch globally August 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One trap in that table deserves its own sentence. Google will support migrating a Limited Distribution account to Full Distribution, but not the reverse, so a team that starts on Limited to avoid the ID step cannot quietly walk it back later. Choose the account type once, with the distribution plan you actually have.&lt;/p&gt;

&lt;h2&gt;
  
  
  What users see, and why updates are the real risk
&lt;/h2&gt;

&lt;p&gt;Android is not closing. Google's FAQ says so directly, and the mechanics support it: users can still install apps from unverified developers through a one-time advanced flow that Google scheduled to launch in August 2026. That flow is deliberately slow. The user enables developer mode, passes a check confirming nobody is coaching them, restarts the phone and reauthenticates, waits a one-day protective period, then confirms with biometrics or a device PIN, and finally chooses to enable installs for 7 days or indefinitely. The 24-hour wait exists specifically to break the manufactured urgency that fraudsters rely on. It is completed once per account and carries across to a new device.&lt;/p&gt;

&lt;p&gt;ADB installs are unaffected, with no waiting period, which keeps development and QA workflows intact.&lt;/p&gt;

&lt;p&gt;Here is the part that catches product teams. Unregistered apps can only be installed or updated when the advanced flow is enabled or through ADB. If a user disables the advanced flow, updates to unregistered apps fail. So the cost of missing registration is not only lost new installs in four markets. It is a frozen install base that stops receiving your security patches, on a device population you cannot contact.&lt;/p&gt;

&lt;p&gt;You can check registration status in three places: the Android developer verification page in Play Console, the Package names tab in the Android Developer Console, and Android Studio itself when generating a signed App Bundle or APK, available in Android Studio Panda 4 and higher. Use the Android Studio surface for day-to-day work, because it puts the answer where an engineer will actually see it.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;Indian studios and D2C brands are disproportionately exposed here, for a structural reason: Southeast Asia and Brazil are the export markets Indian app teams have leaned into hardest, and they are exactly the four launch markets. An Indian consumer app with meaningful Indonesian or Thai installs is inside the first enforcement wave even though India itself is not.&lt;/p&gt;

&lt;p&gt;Three practical notes.&lt;/p&gt;

&lt;p&gt;The D-U-N-S requirement lands on the Indian legal entity, not the app. If you ship under a Private Limited company, the D-U-N-S is against that company's registered details, and any mismatch between the name on the Play Console account, the D-U-N-S record and the incorporation certificate becomes a support ticket with a multi-week round trip. Reconcile those three before you apply, not after.&lt;/p&gt;

&lt;p&gt;Agency and white-label arrangements are the second problem. A large share of Indian app work ships under the client's developer account, which means the client owns the registration obligation and your team owns the knowledge of which packages exist. Neither side has the full picture. Whoever reads this first should send the other a package list this week.&lt;/p&gt;

&lt;p&gt;Third, this deadline collides with others. Play's target API level requirements and the Play Billing Library migration have their own dates, and teams that batch all three into one release train will hit the September window with a large, hard-to-test change set. We sequence these separately for exactly that reason, and have written up the adjacent work in our &lt;a href="https://ecorpit.com/android-target-api-36-play-store-deadline-migration-2026/" rel="noopener noreferrer"&gt;Android target API 36 migration guide&lt;/a&gt; and the &lt;a href="https://ecorpit.com/google-play-billing-library-8-migration-deadline-2026/" rel="noopener noreferrer"&gt;Google Play Billing Library 8 migration deadline&lt;/a&gt;. For the day-of checklist rather than the remediation plan, see our &lt;a href="https://ecorpit.com/android-developer-verification-september-2026-checklist/" rel="noopener noreferrer"&gt;Android developer verification September 2026 checklist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cost-wise, the registration itself is trivial: $25 one-time, roughly ₹2,400, against the engineering time to find keystores and reconcile accounts, which is the real number. Teams comparing that effort against a wider build decision may find our breakdown of &lt;a href="https://ecorpit.com/india-vs-us-app-development-cost-2026/" rel="noopener noreferrer"&gt;India versus US app development cost&lt;/a&gt; useful for framing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we would do differently from most teams
&lt;/h2&gt;

&lt;p&gt;Two opinions, offered as engineering judgement rather than as Google guidance.&lt;/p&gt;

&lt;p&gt;Register everything, not just what is in scope. The four-market, seven-store scoping is real, and it is temporary. Global rollout follows in 2027, and the cost of registering a package you did not strictly have to is a form. The cost of discovering an unregisterable package in 2027, because the keystore left with a contractor in 2022, is the app.&lt;/p&gt;

&lt;p&gt;And treat the package inventory as a permanent asset. Most organisations do not have a list of every Android package they ship, with the signing key location and an owner against each. Building one for this deadline takes a few days. Keeping it costs nothing and pays for itself at the next platform requirement, which on the current cadence arrives roughly every quarter. The real cost here is not the registration; it is discovering how little you knew about your own portfolio.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When does Android developer verification start being enforced?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Enforcement begins on 30 September 2026 for users in Brazil, Indonesia, Singapore and Thailand, across seven participating app stores, on certified Android devices running Android 7 or higher. Google has said the requirement will expand globally for all apps on certified Android devices in 2027, after incorporating feedback from partners, users and the developer community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which app stores are included in the first phase?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seven stores participate initially: Google Play, Samsung's Galaxy Store, Xiaomi's GetApps, OPlus's OPPO App Market, vivo's V-Appstore, Honor's HONOR App Market, and Transsion's Palm Store. If you distribute through a store not on that list, or users sideload directly, the verification requirement is not enforced for your apps during this initial phase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need a D-U-N-S number, and how long does it take?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A D-U-N-S number is required if you register as an organisation rather than an individual. It is a nine-digit business identifier issued free by Dun &amp;amp; Bradstreet, and Google's FAQ states the process can take up to 28 days. Start it first, because no part of the remaining work compresses that wait.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens to apps I never register?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unregistered apps are blocked from installation by users on certified Android devices in the applicable regions. Google also warned Play developers to register remaining apps by 30 September 2026 to avoid removal from Google Play globally. Existing installs cannot be updated unless the user has enabled the advanced flow or the install goes through ADB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does registration cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Registration through the Android Developer Console costs a one-time $25 for a Full Distribution account, which Google describes as similar to the existing $25 Play registration fee. The fee is waived for Limited Distribution accounts, aimed at students, teachers and hobbyists, which allow distribution to up to 20 devices without a government ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I automate registration in my CI/CD pipeline?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Google confirmed the APIs are designed for bulk registration and for use directly in continuous integration and deployment pipelines. The Android Developer ID Status API checks package name eligibility and registration status; the Android Developer Console API registers package names and manages keys. Both support OAuth delegation for third-party platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if I have lost the signing key for an old app?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google's FAQ states plainly that if you lose your signing key you will not be able to register your packages, and recommends a secure key management solution. There is no documented recovery path. Apps using Play App Signing are unaffected, because Google already holds the information needed to identify ownership and register them automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can users still install apps from unverified developers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, through a one-time advanced flow that launched in August 2026. The user enables developer mode, confirms nobody is coaching them, restarts and reauthenticates, waits a one-day protective period, then verifies with biometrics or a PIN. They can then enable installs for seven days or indefinitely. ADB installs are unaffected by the waiting period.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT is a Gurugram-based technology consultancy founded in 2021, and this deadline is the kind of unglamorous portfolio work our senior engineering teams handle for app studios and D2C brands shipping into Southeast Asia and Brazil. We build the package inventory across every Play Console and Android Developer Console account you or your clients control, track down and properly archive signing keys, resolve package-name conflicts before they go to review, register through the right console for each app, and wire the Android Developer ID Status API into your CI so new packages cannot ship unregistered. We are CMMI Level 5 appraised, MSME certified and ISO 27001:2022 certified, and we work as a Google partner across Android and Play. If you are not sure how many Android packages your organisation actually ships, &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;contact us&lt;/a&gt; and we will start with the inventory. Related work sits in our &lt;a href="https://ecorpit.com/ecorpit-android-target-api-36-migration-service-india-2026/" rel="noopener noreferrer"&gt;Android target API 36 migration service&lt;/a&gt; and &lt;a href="https://ecorpit.com/ecorpit-android-vitals-anr-crash-remediation-service-india-2026/" rel="noopener noreferrer"&gt;Android vitals remediation service&lt;/a&gt;, and the wider picture in our &lt;a href="https://ecorpit.com/enterprise-mobile-app-development-guide/" rel="noopener noreferrer"&gt;enterprise mobile app development guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://android-developers.googleblog.com/2026/06/android-developer-verification.html" rel="noopener noreferrer"&gt;Android developer verification: building a safer ecosystem together&lt;/a&gt; - Android Developers Blog, 18 June 2026, updated 15 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/developer-verification/guides/faq" rel="noopener noreferrer"&gt;Android developer verification frequently asked questions&lt;/a&gt; - Android Developers, last updated 22 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/developer-verification/guides/android-developer-console" rel="noopener noreferrer"&gt;Register on Android Developer Console&lt;/a&gt; - Android Developers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/developer-verification/guides/limited-distribution" rel="noopener noreferrer"&gt;Limited distribution accounts&lt;/a&gt; - Android Developers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/developer-verification" rel="noopener noreferrer"&gt;Android developer verification overview&lt;/a&gt; - Android Developers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/android-developer-console/answer/16604405?hl=en" rel="noopener noreferrer"&gt;Get started with an Android Developer Console account&lt;/a&gt; - Android Developer Console Help&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/android-developer-console/answer/16561738?hl=en" rel="noopener noreferrer"&gt;Understanding Android developer verification&lt;/a&gt; - Android Developer Console Help&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/06/google-sets-sept-30-deadline-for.html" rel="noopener noreferrer"&gt;Google sets Sept. 30 deadline for Android developer verification in four countries&lt;/a&gt; - The Hacker News, June 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.helpnetsecurity.com/2026/06/19/android-developer-verification-rollout-markets/" rel="noopener noreferrer"&gt;Google sets timeline for Android developer verification enforcement&lt;/a&gt; - Help Net Security, 19 June 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.technology.org/2026/06/19/android-developer-verification-2026-timeline/" rel="noopener noreferrer"&gt;Android developer verification: the 2026 timeline&lt;/a&gt; - Technology.org, 19 June 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.dnb.com/en-us/smb/duns/get-a-duns.html" rel="noopener noreferrer"&gt;Get a D-U-N-S number&lt;/a&gt; - Dun &amp;amp; Bradstreet&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://android-developers.googleblog.com/2026/03/android-developer-verification.html" rel="noopener noreferrer"&gt;Android developer verification: rolling out to all developers on Play Console and Android Developer Console&lt;/a&gt; - Android Developers Blog, March 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.india-briefing.com/news/india-dpdp-compliance-timeline-enforcement-2026-27-44740.html/" rel="noopener noreferrer"&gt;India's DPDP timeline: critical compliance deadlines for 2026-27&lt;/a&gt; - India Briefing, 11 May 2026, source of the US$1 = INR 95.26 reference rate&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.android.com/certified/partners/" rel="noopener noreferrer"&gt;Certified Android partners&lt;/a&gt; - Android&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last updated: 5 August 2026.&lt;/p&gt;

</description>
      <category>android</category>
    </item>
    <item>
      <title>AI agent identity governance: 109 machine identities per human, and what Okta's $200M Permiso deal signals</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 13:05:06 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/ai-agent-identity-governance-109-machine-identities-per-human-and-what-oktas-200m-permiso-deal-26aj</link>
      <guid>https://dev.to/mr_manushukla/ai-agent-identity-governance-109-machine-identities-per-human-and-what-oktas-200m-permiso-deal-26aj</guid>
      <description>&lt;h1&gt;
  
  
  AI agent identity governance: 109 machine identities per human, and what Okta's $200M Permiso deal signals
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; On 30 July 2026 Okta signed a definitive agreement to acquire Permiso Security, a platform that detects threats across human, non-human and agentic identities; a source told TechCrunch the price was about $200 million. The number that explains the deal comes from a different vendor: Palo Alto Networks' 2026 Identity Security Landscape report puts the average enterprise at 109 machine identities for every human identity, with respondents expecting AI agent counts to grow 85% over the next 12 months. Check Point's 2026 Cloud Security Report found 64% of organisations already run AI agents in pilot or production and 12% have granted them privileged access to critical systems. Microsoft priced its answer in May: Agent 365 went generally available on 1 May 2026 at $15 per user per month, licensed per human user rather than per agent. For Indian companies there is a second clock: using AI for sizable decision-making or profiling is one of the criteria that can make you a Significant Data Fiduciary under the DPDP framework, which brings a mandatory DPO, an independent audit and a DPIA, with penalties reaching ₹250 crore.&lt;/p&gt;

&lt;p&gt;The strategic read is simple. Identity vendors have concluded that authentication is no longer the control that matters, because agents authenticate correctly and then do something unexpected. What they are racing to sell is runtime behaviour: what did this agent actually touch, and can you stop it in the next few seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Okta actually bought
&lt;/h2&gt;

&lt;p&gt;Permiso is a cloud-native identity security platform covering human, non-human and agentic identities across multi-cloud environments. Okta's announcement describes the detection surface in unusually specific terms: more than 2,500 research-driven signals across over 70 identity partners, used to surface overprivileged access, unused permissions, anomalous agent behaviour and tool usage, policy violations, and high blast-radius behaviour in real time.&lt;/p&gt;

&lt;p&gt;Four capabilities are named for after the close. Detection across all identity types by combining authentication signals with behavioural analytics. Continuous identification of risky behaviour across AI agents running locally, on SaaS platforms or in cloud environments. A dynamic sandbox called SandyClaw that detonates AI agent skills and prompts to catch AI supply-chain attacks before they reach customer environments. And automated response that investigates and contains compromised or misconfigured agents in real time.&lt;/p&gt;

&lt;p&gt;The third of those is the one worth pausing on. Sandboxing an agent &lt;em&gt;skill&lt;/em&gt; treats the skill file the way endpoint security treats an executable: unknown code from a third party, detonated before it runs. That is a different mental model from prompt filtering, and it is a direct response to the supply-chain pattern the industry has been living through, from poisoned packages to poisoned agent instructions.&lt;/p&gt;

&lt;p&gt;Permiso's P0 Labs research team joins Okta alongside Okta Threat Intelligence. The transaction is expected to close in the third quarter of Okta's fiscal year 2027 and Okta said it expects no impact on the guidance it issued on 27 May 2026.&lt;/p&gt;

&lt;p&gt;Ely Kahn, Chief Product Officer at Okta, framed the purchase around the mixed workforce: "We're thrilled to welcome Permiso to Okta as we help companies secure their agentic enterprises where humans, applications, service accounts, and AI agents work together."&lt;/p&gt;

&lt;p&gt;The customer voice in the same announcement is more useful than the vendor one. Sebastian Goodwin, Chief Trust Officer at Autodesk, said: "When you need to secure enterprise AI at scale, visibility and threat detection are non-negotiable. Permiso gives Autodesk the ability to discover and monitor all identities across our environment, making it an important part of our broader cloud security strategy." Discover and monitor. Not authenticate. That is the shift.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number everyone quotes, and why it is four different numbers
&lt;/h2&gt;

&lt;p&gt;Every vendor deck in this category opens with a machine-to-human identity ratio. They do not agree, and the spread is wide enough to change what you budget.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Reported ratio&lt;/th&gt;
&lt;th&gt;Published&lt;/th&gt;
&lt;th&gt;What that tells you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Palo Alto Networks, 2026 Identity Security Landscape&lt;/td&gt;
&lt;td&gt;109 machine identities per human&lt;/td&gt;
&lt;td&gt;May 2026&lt;/td&gt;
&lt;td&gt;The figure most cited in 2026 agent-identity marketing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitGuardian, 2026 State of Secrets Sprawl&lt;/td&gt;
&lt;td&gt;80 to 1&lt;/td&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;Counts through the lens of leaked and sprawling secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ManageEngine, 2026 Identity Security Outlook&lt;/td&gt;
&lt;td&gt;100 to 1, with some organisations at 500 to 1&lt;/td&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;Shows how much the tail matters; averages hide the worst case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KPMG, 2026 Cybersecurity Considerations&lt;/td&gt;
&lt;td&gt;80 to 1 in the average enterprise&lt;/td&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;Advisory framing aimed at CISOs and boards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composite of four published 2025-2026 ratios&lt;/td&gt;
&lt;td&gt;Roughly 79 to 1, median 77 to 1&lt;/td&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;The averages land well below the headline figure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The honest reading is that nobody is counting the same thing. Some counts include every TLS certificate and service account; others count only credentialed workload identities. Treat any single ratio as a directional argument for funding, not as an input to a capacity model. Then go count your own, because your number is the only one that determines how big the problem is for you.&lt;/p&gt;

&lt;p&gt;What the Palo Alto data adds beyond the headline is the growth split: respondents expect AI agents to grow 85% over the next 12 months, machine identities 77%, and human identities 56%. Every category is growing. Agents are simply growing fastest, off a base that is already ungoverned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The control gap is not a detection gap, it is a lifecycle gap
&lt;/h2&gt;

&lt;p&gt;Palo Alto's respondents could mostly explain the purpose of their AI agents. Far fewer could define what those agents can access, how that access is limited, when permissions get revoked, or which systems can inherit that access. Environments still lack behavioural monitoring, credential revocation and shutdown mechanisms for agents, and they continue to rely on permanent privileged access rather than just-in-time controls.&lt;/p&gt;

&lt;p&gt;The same report describes an executive perception gap worth quoting to your own leadership: C-suite executives believe their companies enforce least privilege because they are looking at human access, while security practitioners disagree because machines and automated systems run a growing share of operations.&lt;/p&gt;

&lt;p&gt;Check Point's survey data lines up. Only 5% of respondents said they have full visibility into which AI tools employees use, how those tools are accessed, and where sensitive data goes once it enters an AI system. Only 17% said they have broadly deployed runtime controls that inspect and enforce policy on LLM inputs and outputs. Only 22% said their web application firewall or WAAP is effective against GenAI-specific attacks such as prompt injection, while 71% reported more false positives after adopting generative AI workloads. And 42% said workers bypass AI security controls when those controls slow them down.&lt;/p&gt;

&lt;p&gt;Put those next to the adoption figures — 64% with agents in pilot or production, 12% with agents holding privileged access to critical systems — and the shape of the problem is clear. Deployment is ahead of instrumentation by a wide margin. Check Point's own summary of the gap: 77% of organisations have changed their security strategy in response to AI, but only 26% believe their architecture can actually support AI workloads without a major redesign, a 51-point readiness gap.&lt;/p&gt;

&lt;p&gt;Fragmentation makes the response slower too. Unit 42 examined more than 750 cyber incidents in 2025 and found that 87% required evidence from two or more distinct sources to establish what happened, with complex incidents needing as many as 10. Practitioners reported that fragmented tooling adds an average of 12 hours to identity-related incidents. Twelve hours is a long time when the actor on the other side is a process, not a person.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the platforms actually ship
&lt;/h2&gt;

&lt;p&gt;Three approaches are on the table in 2026. This is where they differ.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Okta plus Permiso (after close)&lt;/th&gt;
&lt;th&gt;Microsoft Agent 365 with Entra Agent ID&lt;/th&gt;
&lt;th&gt;Build it yourself&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent registry and lifecycle&lt;/td&gt;
&lt;td&gt;Identity security fabric extended across human, non-human and agentic identities&lt;/td&gt;
&lt;td&gt;Register agent identities in Entra; manage lifecycle and access packages through Identity Governance&lt;/td&gt;
&lt;td&gt;A table in your own directory, plus whatever your framework exposes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy at access time&lt;/td&gt;
&lt;td&gt;Authentication signals combined with behavioural analytics&lt;/td&gt;
&lt;td&gt;Conditional Access applied to agent access attempts; requires an Agent 365 licence&lt;/td&gt;
&lt;td&gt;Your own gateway, enforced per call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime behaviour detection&lt;/td&gt;
&lt;td&gt;Over 2,500 signals across 70+ identity partners, including anomalous agent behaviour and tool usage&lt;/td&gt;
&lt;td&gt;Agent sign-in signals feed Identity Protection&lt;/td&gt;
&lt;td&gt;Your own telemetry pipeline and detection rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skill and prompt inspection&lt;/td&gt;
&lt;td&gt;SandyClaw dynamic sandbox detonation for agent skills and prompts&lt;/td&gt;
&lt;td&gt;Not described as a sandbox in the GA announcement&lt;/td&gt;
&lt;td&gt;Static review, if anyone has time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated containment&lt;/td&gt;
&lt;td&gt;Investigate and contain compromised or misconfigured agents in real time&lt;/td&gt;
&lt;td&gt;Governance and protection through the Entra stack&lt;/td&gt;
&lt;td&gt;Custom kill-switch, usually a manual runbook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commercial model&lt;/td&gt;
&lt;td&gt;Capabilities land after the deal closes in Okta's fiscal Q3 2027&lt;/td&gt;
&lt;td&gt;$15 per user per month standalone, also included with Microsoft 365 E7, licensed per human user&lt;/td&gt;
&lt;td&gt;Engineering time, ongoing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things stand out. First, Microsoft's per-human-user licensing means your bill tracks headcount rather than agent count, which is generous if you run many agents per person and expensive if you run few. Second, Okta's most differentiated capability, skill sandboxing, is not available to you today: it arrives when the transaction closes, expected in Okta's fiscal Q3 2027. If you have agents in production now, you are building or buying something in the interim regardless.&lt;/p&gt;

&lt;p&gt;The pattern in both roadmaps is the same and it is the useful takeaway even if you buy neither. Agent governance is being assembled out of four layers: a registry, a policy point at access time, runtime behavioural telemetry, and a containment action. If you are building, build those four. If you are buying, ask which of the four the product actually covers today rather than on a slide.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 90-day build order
&lt;/h2&gt;

&lt;p&gt;You do not need a platform decision to start. You need an inventory, because every subsequent control depends on it, and because the vendors' own data says most organisations cannot answer the first question.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;What to do&lt;/th&gt;
&lt;th&gt;Evidence you can show an auditor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Days 1-15&lt;/td&gt;
&lt;td&gt;Enumerate every credential an agent holds: model provider keys, database roles, SaaS tokens, internal API clients&lt;/td&gt;
&lt;td&gt;A list of agent identities with an owner, a purpose and an expiry per credential&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 16-30&lt;/td&gt;
&lt;td&gt;Give every agent its own identity. No shared service accounts, no borrowed human credentials&lt;/td&gt;
&lt;td&gt;A one-to-one mapping between running agents and directory principals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 31-45&lt;/td&gt;
&lt;td&gt;Scope permissions to the narrowest set that keeps the agent working, and remove standing privilege&lt;/td&gt;
&lt;td&gt;A before-and-after permission diff per agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 46-60&lt;/td&gt;
&lt;td&gt;Log every tool call the agent makes, with the identity, the target and the parameters&lt;/td&gt;
&lt;td&gt;Queryable tool-call telemetry with a retention period&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 61-75&lt;/td&gt;
&lt;td&gt;Write the kill switch and test it. Revoking one agent must not take down the fleet&lt;/td&gt;
&lt;td&gt;A timed drill record showing revocation and recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 76-90&lt;/td&gt;
&lt;td&gt;Set alert thresholds on blast-radius behaviour: new target systems, permission escalation, unusual call volume&lt;/td&gt;
&lt;td&gt;Alert definitions plus at least one tuned true positive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of these are commonly skipped and both are the expensive ones to retrofit. Per-agent identity is skipped because a shared service account is faster on day one, and it destroys attribution permanently: once three agents share a principal you cannot answer which one touched the record. Tool-call logging is skipped because the volume looks frightening, and without it the containment step has nothing to trigger on.&lt;/p&gt;

&lt;p&gt;The kill-switch drill deserves a specific note. Most teams discover during the drill that revoking an agent's credential also breaks a batch job, a webhook receiver and a dashboard, because the same credential was quietly reused. Finding that in a drill costs an afternoon. Finding it during an incident costs the incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why authentication stopped being the control
&lt;/h2&gt;

&lt;p&gt;The reason identity vendors are buying detection companies is that the failure mode changed. A compromised human account looks wrong at login: strange geography, strange device, strange hour. A compromised agent looks perfect at login, because it is using the credential it was issued, from the infrastructure it always runs on, at a time it always runs. Everything anomalous happens afterwards.&lt;/p&gt;

&lt;p&gt;Palo Alto's report states this plainly: single sign-on and multi-factor authentication help secure logins, but they do not control what users, tokens, connectors or automated systems can reach after authentication. More than half of participants said they cannot consistently enforce least privilege for service accounts across cloud, SaaS and on-premises systems.&lt;/p&gt;

&lt;p&gt;This is the same lesson the agent framework CVEs taught from the other direction. When we walked through the &lt;a href="https://ecorpit.com/langgraph-checkpointer-rce-cve-audit-patch-2026/" rel="noopener noreferrer"&gt;LangGraph checkpointer RCE chain&lt;/a&gt;, the damage estimate had nothing to do with the CVSS score and everything to do with what credentials sat in the runtime the payload landed in. Blast radius is the unit of analysis. An agent's identity is just the ledger of that blast radius, which is why governing it is the highest-use control available.&lt;/p&gt;

&lt;p&gt;That framing also decides build-versus-buy. If your agents hold three read-only API keys, a directory entry and good logging get you most of the way, and a per-user licence is hard to justify. If your agents hold write access to a payments system or a patient record store, you are in the 12% Check Point described, and the runtime detection layer is not optional. We work through the layer model in more depth in &lt;a href="https://ecorpit.com/enterprise-ai-agent-governance-layers-2026/" rel="noopener noreferrer"&gt;enterprise AI agent governance layers&lt;/a&gt; and, for fleets, in &lt;a href="https://ecorpit.com/enterprise-ai-agent-governance-multi-agent-2026/" rel="noopener noreferrer"&gt;governing multi-agent systems&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not solve
&lt;/h2&gt;

&lt;p&gt;Identity governance bounds what an agent can reach. It does nothing about what an agent can be persuaded to do inside those bounds. An agent with legitimate access to a customer database, hijacked by an injected instruction, produces perfectly authorised queries that exfiltrate exactly what it was allowed to see. No amount of least privilege catches that, because the access was granted.&lt;/p&gt;

&lt;p&gt;The two controls are complements, not substitutes. Identity governance decides the ceiling; input-handling controls decide the behaviour under that ceiling. Teams that buy one and skip the other tend to skip the second, which is why we treat &lt;a href="https://ecorpit.com/ai-agent-security-prompt-injection-guardrails-2026/" rel="noopener noreferrer"&gt;prompt injection guardrails for AI agents&lt;/a&gt; as a separate workstream with its own owner.&lt;/p&gt;

&lt;p&gt;The other unresolved problem is delegated authority. When an agent acts for a user, whose permissions apply, and how does the downstream system tell? Okta's Cross App Access work, announced with an expanding partner ecosystem on 23 June 2026, is aimed at this, and Microsoft's per-human-user licensing implicitly assumes an agent is always acting on someone's behalf. Neither is a finished answer. Until one exists, write down the delegation model your agents use, because your auditor will ask and the honest answer today is usually "the agent has its own standing rights and we call that delegation".&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;There is a compliance trigger here that Indian teams keep missing, and it does not depend on the size of your agent fleet.&lt;/p&gt;

&lt;p&gt;Under the DPDP framework, an organisation can be designated a Significant Data Fiduciary on any of several criteria, and one of them is risk profile: processing sensitive data such as health or finance information, or using AI for sizable decision-making or profiling. The other two common triggers are processing the data of 5 million or more residents and annual turnover of INR 2.5 billion, roughly US$26.24 million. A mid-size Indian company that would never hit the user-count or turnover thresholds can land inside SDF scope purely by putting a decisioning agent into a customer workflow.&lt;/p&gt;

&lt;p&gt;The obligations that follow are concrete and dated. By the first quarter of 2027, SDFs are expected to have appointed an India-based Data Protection Officer reporting to the board, engaged an independent data auditor, and completed a Data Protection Impact Assessment for high-risk processing. Full enforcement, with the Data Protection Board of India exercising its adjudicatory powers and penalties up to INR 2.5 billion for major violations, is widely expected on 13-14 May 2027. Soft enforcement is expected to end around November 2026.&lt;/p&gt;

&lt;p&gt;Three practical consequences for an Indian engineering team running agents. Your agent inventory is DPIA input, so build it in a form an auditor can read rather than a spreadsheet someone maintains by hand. Your tool-call logs are the evidence that supports "we can demonstrate what accessed this personal data", which is the hardest claim to retrofit. And per-agent identity is what makes a breach report specific instead of speculative, because "one of our agents" is not an answer a regulator accepts. The wider sequencing sits in our &lt;a href="https://ecorpit.com/dpdp-act-engineering-playbook-indian-startups-2026/" rel="noopener noreferrer"&gt;DPDP Act engineering playbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One more India-specific note on cost. The per-human-user licensing model that Microsoft chose is comparatively favourable for Indian teams, where agent-to-engineer ratios tend to run high in cost-conscious builds. Do the arithmetic on your actual agent count before assuming a per-agent model would have been cheaper. For the broader production readiness picture, see our guide to &lt;a href="https://ecorpit.com/enterprise-ai-agents-production-use-cases-2026/" rel="noopener noreferrer"&gt;enterprise AI agents in production&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What did Okta announce about Permiso Security?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On 30 July 2026 Okta signed a definitive agreement to acquire Permiso Security, a cloud-native platform that detects and mitigates threats across human, non-human and agentic identities in multi-cloud environments. A source told TechCrunch the price was about $200 million. The transaction is expected to close in the third quarter of Okta's fiscal year 2027.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many machine identities does a typical enterprise have?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Palo Alto Networks' 2026 Identity Security Landscape report puts the average at 109 machine identities per human identity. Other 2026 reports disagree: GitGuardian and KPMG both publish 80 to 1, and ManageEngine reports 100 to 1 with some organisations reaching 500 to 1. Count your own environment rather than adopting a vendor figure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does Microsoft Agent 365 cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Agent 365 became generally available on 1 May 2026 at $15 per user per month as a standalone licence, and it is also included with Microsoft 365 E7. It is licensed per human user, meaning the person who manages, sponsors or is served by an agent, rather than per agent. Conditional Access for agents requires that licence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is authentication no longer enough for AI agents?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A compromised agent authenticates correctly, from its usual infrastructure, at its usual time, so nothing looks wrong at login. Palo Alto's report notes that single sign-on and multi-factor authentication do not control what tokens, connectors or automated systems reach after authentication. Detection has to move to runtime behaviour rather than credential presentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is SandyClaw and why does it matter?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SandyClaw is Permiso's dynamic sandbox for AI agent skills, described by Okta as the first platform to bring dynamic sandbox detonation to agent skills. It uses behavioural analysis and a multi-engine detection stack to catch AI supply-chain attacks in agent skills and prompts before they reach customer environments, treating third-party skills like untrusted executables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can deploying AI agents make an Indian company an SDF?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, potentially. Significant Data Fiduciary designation criteria include a risk profile based on processing sensitive health or financial data, or using AI for sizable decision-making or profiling. That is independent of the 5 million resident and INR 2.5 billion turnover thresholds, so a mid-size company can enter scope through a decisioning agent alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should we build first if we cannot buy a platform yet?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start with an inventory of every credential each agent holds, then give every agent its own directory identity rather than a shared service account. Attribution is impossible to retrofit once agents share a principal. After that, scope permissions down, log every tool call, and test a per-agent kill switch under drill conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does identity governance stop prompt injection?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Identity governance bounds what an agent can reach; it does not change what the agent does inside those bounds. A hijacked agent with legitimate database access issues perfectly authorised queries. Input-handling controls and identity controls are complements, and teams that buy only one usually skip the input-handling side.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT's senior engineering teams build and govern production AI agent systems for companies in India and abroad. The work described above is what we do: inventory the credentials your agents actually hold, give each agent its own identity and a scoped permission set, instrument tool-call telemetry an auditor can read, and drill the kill switch before you need it. We are ISO 27001:2022 certified and CMMI Level 5 appraised, and we design applications aligned with DPDP requirements. If you have agents in production and no answer to "what can this one reach", &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;contact us&lt;/a&gt; and we will scope an agent identity review.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.okta.com/newsroom/press-releases/okta-signs-definitive-agreement-to-acquire-permiso-security/" rel="noopener noreferrer"&gt;Okta signs definitive agreement to acquire Permiso Security&lt;/a&gt; - Okta newsroom, 30 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://techcrunch.com/2026/07/30/okta-buys-ai-security-startup-permiso-source-says-for-about-200m/" rel="noopener noreferrer"&gt;Okta buys AI security startup Permiso, source says for about $200M&lt;/a&gt; - TechCrunch, 30 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cyberscoop.com/okta-acquires-permiso-security-ai-identity-threat-detection/" rel="noopener noreferrer"&gt;Okta acquires Permiso for AI identity threat detection&lt;/a&gt; - CyberScoop, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.helpnetsecurity.com/2026/05/14/2026-identity-security-landscape-report/" rel="noopener noreferrer"&gt;Machine identities outnumber humans 109 to 1&lt;/a&gt; - Help Net Security on the Palo Alto Networks 2026 Identity Security Landscape report, 14 May 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.unite.ai/check-points-2026-cloud-security-report-securing-the-ai-transformation-warns-enterprise-security-is-falling-behind-ai-adoption/" rel="noopener noreferrer"&gt;Check Point's 2026 Cloud Security Report: Securing the AI Transformation&lt;/a&gt; - Unite.AI summary of the Check Point and Cybersecurity Insiders survey, 26 May 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.checkpoint.com/press-releases/ai-adoption-creates-critical-cloud-security-gaps-for-enterprises-new-check-point-report-shows/" rel="noopener noreferrer"&gt;AI adoption creates critical cloud security gaps for enterprises&lt;/a&gt; - Check Point Software press release, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://techcommunity.microsoft.com/blog/microsoft_365blog/microsoft-365-e7-and-agent-365-are-now-generally-available/4516295" rel="noopener noreferrer"&gt;Microsoft 365 E7 and Agent 365 are now generally available&lt;/a&gt; - Microsoft 365 Blog, 1 May 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/entra/id-governance/agent-id-governance-overview" rel="noopener noreferrer"&gt;Governing agent identities: Microsoft Entra ID Governance&lt;/a&gt; - Microsoft Learn&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/microsoft-agent-365/overview" rel="noopener noreferrer"&gt;Microsoft Agent 365 overview&lt;/a&gt; - Microsoft Learn&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.csoonline.com/article/4125156/why-non-human-identities-are-your-biggest-security-blind-spot-in-2026.html" rel="noopener noreferrer"&gt;Why non-human identities are your biggest security blind spot in 2026&lt;/a&gt; - CSO Online, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://axis-intelligence.com/machine-identity-statistics/" rel="noopener noreferrer"&gt;Machine identity statistics 2026: non-human identity ratios and secrets sprawl&lt;/a&gt; - Axis Intelligence composite of published 2025-2026 ratios&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nhimg.org/nhi-news/kpmg-2026-non-human-identity-security-ciso-priorities" rel="noopener noreferrer"&gt;KPMG 2026 cybersecurity report identifies non-human identities as a critical CISO priority&lt;/a&gt; - Non-Human Identity news, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.india-briefing.com/news/india-dpdp-compliance-timeline-enforcement-2026-27-44740.html/" rel="noopener noreferrer"&gt;India's DPDP timeline: critical compliance deadlines for 2026-27&lt;/a&gt; - India Briefing, 11 May 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.okta.com/newsroom/press-releases/okta-announces-cross-app-access-partners/" rel="noopener noreferrer"&gt;Okta advances the industry standard for secure AI agent connections with expanding Cross App Access ecosystem&lt;/a&gt; - Okta newsroom, 23 June 2026&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last updated: 5 August 2026.&lt;/p&gt;

</description>
      <category>aiagents</category>
    </item>
    <item>
      <title>3 LangGraph CVEs chain to RCE: the checkpointer version matrix and a 30-minute audit</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 12:59:19 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/3-langgraph-cves-chain-to-rce-the-checkpointer-version-matrix-and-a-30-minute-audit-1e0d</link>
      <guid>https://dev.to/mr_manushukla/3-langgraph-cves-chain-to-rce-the-checkpointer-version-matrix-and-a-30-minute-audit-1e0d</guid>
      <description>&lt;h1&gt;
  
  
  3 LangGraph CVEs chain to RCE: the checkpointer version matrix and a 30-minute audit
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; Three now-patched LangGraph flaws let an attacker walk from a metadata filter string to code execution on a self-hosted agent server. Check Point researcher Yarden Porat reported all three: CVE-2025-67644 (CVSS 7.3, SQL injection in the SQLite checkpointer), CVE-2026-28277 (CVSS 6.8, unsafe msgpack deserialization in LangGraph itself) and CVE-2026-27022 (CVSS 6.5, RediSearch query injection in the JavaScript Redis checkpointer). The first two chain. The Hacker News published the details on 12 June 2026; the msgpack advisory, GHSA-g48c-2wqr-h844, went to the GitHub Advisory Database on 5 March 2026 with CWE-502 and an EPSS score of 0.332%. Fixed versions are &lt;code&gt;langgraph-checkpoint-sqlite&lt;/code&gt; 3.0.1, &lt;code&gt;langgraph&lt;/code&gt; 1.0.10 and &lt;code&gt;@langchain/langgraph-checkpoint-redis&lt;/code&gt; 1.0.2. LangChain's managed LangSmith Deployment is not affected.&lt;/p&gt;

&lt;p&gt;The reason this matters more than the CVSS numbers suggest: Check Point's 2026 Cloud Security Report found 64% of organisations already have AI agents in pilot or production and 12% have granted those agents privileged access to core systems. An agent runtime holds LLM API keys, database credentials and conversation state. In India, personal data sitting in that state is squarely inside the Digital Personal Data Protection Act 2023, where the Data Protection Board can levy up to ₹250 crore (about $26 million) per major violation. A checkpoint table is not a cache. It is a credential-adjacent datastore that your application deserialises into live Python objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually broke
&lt;/h2&gt;

&lt;p&gt;LangGraph persists agent state as checkpoints. Every superstep writes a serialised snapshot of the graph's channels to whatever backing store you configured, and &lt;code&gt;get_state_history()&lt;/code&gt; reads them back so an agent can resume, branch or replay a thread. The three flaws sit at two different layers of that path: the query that finds a checkpoint, and the decoder that turns its bytes back into objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2025-67644: SQL injection through metadata filter keys
&lt;/h3&gt;

&lt;p&gt;The SQLite checkpointer's &lt;code&gt;_metadata_predicate()&lt;/code&gt; builds its WHERE clause with f-string interpolation. User-supplied metadata filter keys land directly in the SQL text, including inside &lt;code&gt;json_extract&lt;/code&gt; expressions, with no parameterisation and no escaping. Any application that passes an untrusted filter dictionary into a checkpoint search hands the attacker query control. GitLab's advisory database records the affected range as &lt;code&gt;langgraph-checkpoint-sqlite&lt;/code&gt; 3.0.0 and below, fixed in 3.0.1, carrying a CVSS score of 7.3 under GHSA-9rwj-6rc7-p77c.&lt;/p&gt;

&lt;p&gt;On its own, this leaks. An attacker bypasses the thread filter and reads every checkpoint row in the table: other users' conversation state, thread identifiers, whatever metadata your graph writes. For a multi-tenant agent that is already a reportable incident.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-28277: msgpack deserialisation that rebuilds arbitrary Python objects
&lt;/h3&gt;

&lt;p&gt;LangGraph's &lt;code&gt;JsonPlusSerializer&lt;/code&gt; encodes checkpoints as msgpack, and its decoder handles extension types by reconstructing Python objects. The GitHub advisory describes the pattern as equivalent to &lt;code&gt;getattr(importlib.import_module(module_name), callable_name)(arguments)&lt;/code&gt;. Any importable callable, invoked with attacker-supplied arguments. That includes &lt;code&gt;os.system&lt;/code&gt; and &lt;code&gt;subprocess.Popen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The advisory rates it Moderate at 6.8, with the vector &lt;code&gt;CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H&lt;/code&gt;, and is explicit that it is a defence-in-depth issue: exploitation requires the ability to write attacker-controlled checkpoint bytes at rest. Affected versions are &lt;code&gt;langgraph&lt;/code&gt; 1.0.9 and below; the fix shipped in 1.0.10 on 5 March 2026. LangGraph's own note says there is no evidence of exploitation in the wild.&lt;/p&gt;

&lt;h3&gt;
  
  
  CVE-2026-27022: RediSearch query injection in the JavaScript checkpointer
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;RedisSaver&lt;/code&gt; and &lt;code&gt;ShallowRedisSaver&lt;/code&gt; classes in &lt;code&gt;@langchain/langgraph-checkpoint-redis&lt;/code&gt; interpolate user-provided filter keys and values straight into RediSearch queries. RediSearch treats characters like &lt;code&gt;@&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt; as syntax, so an attacker who controls a filter value can rewrite the query logic and bypass the access controls that were supposed to scope results to one thread. It is CWE-74, CVSS 6.5, vector &lt;code&gt;CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N&lt;/code&gt;, published to NVD on 20 February 2026 under GHSA-5mx2-w598-339m. The fix, in pull request 1943, adds an &lt;code&gt;escapeRediSearchTagValue&lt;/code&gt; utility and also hardens the MongoDB checkpoint path by rejecting non-primitive filter values, which closes a parallel MongoDB operator-injection hole.&lt;/p&gt;

&lt;p&gt;One version discrepancy worth knowing before you write a ticket. The Hacker News, citing the GitHub advisory, gives the affected range as versions before 1.0.1. SentinelOne's vulnerability database and the linked release tag both point at 1.0.2. Pin 1.0.2 or later and the argument goes away.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the chain works
&lt;/h2&gt;

&lt;p&gt;Read the second and third bullets slowly, because this is where a "requires privileged write access" advisory quietly stops requiring privileged write access.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The attacker builds a msgpack payload whose extension type names a dangerous callable and its arguments.&lt;/li&gt;
&lt;li&gt;The attacker sends a malicious filter parameter to an endpoint that reaches &lt;code&gt;get_state_history()&lt;/code&gt;, exploiting CVE-2025-67644 so the SQL query returns a fabricated checkpoint row whose &lt;code&gt;checkpoint&lt;/code&gt; column contains that payload.&lt;/li&gt;
&lt;li&gt;The application processes the result set and deserialises the BLOB.&lt;/li&gt;
&lt;li&gt;CVE-2026-28277 reconstructs the attacker's object. The payload runs inside the agent runtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The attacker never needed write access to the database. The SQL injection manufactures the row inside the query result. That is the whole trick, and it is why triaging CVE-2026-28277 in isolation as "post-exploitation only" gets the priority wrong on any deployment that also runs an unpatched SQLite checkpointer with user-influenced filters.&lt;/p&gt;

&lt;p&gt;Check Point's write-up puts the exposure boundary plainly: the chain is exploitable in self-hosted deployments using the SQLite or Redis checkpointer with user-controlled filter input, and LangChain's managed platform is not affected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which deployments are actually exposed
&lt;/h2&gt;

&lt;p&gt;Most teams do not know which checkpointer their staging cluster is running, because it was chosen in week one of a prototype and never revisited. Start here.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Checkpointer backend&lt;/th&gt;
&lt;th&gt;Affected by&lt;/th&gt;
&lt;th&gt;Minimum safe version&lt;/th&gt;
&lt;th&gt;What to check first&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;langgraph-checkpoint-sqlite&lt;/code&gt; (Python)&lt;/td&gt;
&lt;td&gt;CVE-2025-67644 and CVE-2026-28277&lt;/td&gt;
&lt;td&gt;3.0.1, plus &lt;code&gt;langgraph&lt;/code&gt; 1.0.10&lt;/td&gt;
&lt;td&gt;Whether any HTTP handler passes a request-derived dict into a checkpoint search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@langchain/langgraph-checkpoint-redis&lt;/code&gt; (JS)&lt;/td&gt;
&lt;td&gt;CVE-2026-27022&lt;/td&gt;
&lt;td&gt;1.0.2&lt;/td&gt;
&lt;td&gt;Filter values reaching &lt;code&gt;RedisSaver&lt;/code&gt; or &lt;code&gt;ShallowRedisSaver&lt;/code&gt; without escaping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MongoDB checkpoint (JS)&lt;/td&gt;
&lt;td&gt;Operator injection hardened in the same patch&lt;/td&gt;
&lt;td&gt;Ship with the 1.0.2 release train&lt;/td&gt;
&lt;td&gt;Filter values that are objects rather than primitives&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL checkpointer&lt;/td&gt;
&lt;td&gt;Not named in these three advisories&lt;/td&gt;
&lt;td&gt;Current &lt;code&gt;langgraph&lt;/code&gt; 1.0.10&lt;/td&gt;
&lt;td&gt;Still patch &lt;code&gt;langgraph&lt;/code&gt; itself for the msgpack decoder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In-memory / no persistence&lt;/td&gt;
&lt;td&gt;Not exposed via a store&lt;/td&gt;
&lt;td&gt;Current &lt;code&gt;langgraph&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Nothing persists, but review any custom serializer hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LangSmith Deployment (managed)&lt;/td&gt;
&lt;td&gt;Not affected&lt;/td&gt;
&lt;td&gt;Managed by LangChain&lt;/td&gt;
&lt;td&gt;Confirm you are genuinely on the managed plane, not a self-hosted copy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The row that catches people is PostgreSQL. Teams read "SQLite and Redis" and close the ticket. The msgpack decoder lives in &lt;code&gt;langgraph&lt;/code&gt;, not in the SQLite package, so a Postgres-backed deployment on &lt;code&gt;langgraph&lt;/code&gt; 1.0.9 still deserialises checkpoints unsafely. It simply lacks the SQL injection that would let an unauthenticated caller forge a row. If your Postgres credentials leak, or a batch job with write access is compromised, the deserialisation path is right there.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-minute audit
&lt;/h2&gt;

&lt;p&gt;Run this against every environment that resumes agent state, including the staging cluster nobody owns. Each step is a single command and a pass criterion.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Pass criterion&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Inventory Python packages&lt;/td&gt;
&lt;td&gt;`pip list \&lt;/td&gt;
&lt;td&gt;grep -Ei "langgraph\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Inventory the SQLite checkpointer&lt;/td&gt;
&lt;td&gt;{% raw %}&lt;code&gt;pip show langgraph-checkpoint-sqlite&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Version 3.0.1 or later, or the package is absent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Inventory the JS checkpointer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm list @langchain/langgraph-checkpoint-redis&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Version 1.0.2 or later, or the package is absent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Find untrusted filter paths&lt;/td&gt;
&lt;td&gt;`grep -rn "get_state_history\&lt;/td&gt;
&lt;td&gt;aget_state_history" --include=*.py .`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Check the JS filter paths&lt;/td&gt;
&lt;td&gt;`grep -rn "RedisSaver\&lt;/td&gt;
&lt;td&gt;ShallowRedisSaver" --include=&lt;em&gt;.ts --include=&lt;/em&gt;.js .`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Confirm strict mode&lt;/td&gt;
&lt;td&gt;`env \&lt;/td&gt;
&lt;td&gt;grep LANGGRAPH_STRICT_MSGPACK`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. Look for custom decoder hooks&lt;/td&gt;
&lt;td&gt;`grep -rn "ext_hook\&lt;/td&gt;
&lt;td&gt;JsonPlusSerializer(" --include=*.py .`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8. Review store write access&lt;/td&gt;
&lt;td&gt;List IAM principals and service accounts with write on the checkpoint store&lt;/td&gt;
&lt;td&gt;Only the agent runtime and one break-glass role&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Steps 4 and 5 are the ones that decide your severity. If no user-controlled string reaches a filter key, you have a patching task. If one does, and you are below the fixed versions, you have an incident-response task and the order of operations changes: contain first, rotate the credentials the runtime can reach, then patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hardening past the patch
&lt;/h2&gt;

&lt;p&gt;Upgrading closes the injection. It does not, by itself, stop the decoder from rebuilding arbitrary types, because the default policy after the patch is still permissive. LangGraph shipped an allowlist mechanism alongside the fix, and it has three states.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting for &lt;code&gt;allowed_msgpack_modules&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;th&gt;When to use it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;True&lt;/code&gt; (default when strict mode is off)&lt;/td&gt;
&lt;td&gt;Reconstructs all extension types, logs a warning for unregistered ones&lt;/td&gt;
&lt;td&gt;Local development only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;None&lt;/code&gt; (strict)&lt;/td&gt;
&lt;td&gt;Reconstructs only the built-in safe set, blocks everything else&lt;/td&gt;
&lt;td&gt;Production default, once you have read the warnings from a staging run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[(module, class_name), ...]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Built-in safe set plus exactly the listed symbols, matched exactly&lt;/td&gt;
&lt;td&gt;Production, when strict mode breaks a legitimate custom type&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Setting the environment variable &lt;code&gt;LANGGRAPH_STRICT_MSGPACK&lt;/code&gt; to a truthy value (&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;yes&lt;/code&gt;) flips &lt;code&gt;JsonPlusSerializer()&lt;/code&gt; to default &lt;code&gt;allowed_msgpack_modules&lt;/code&gt; to &lt;code&gt;None&lt;/code&gt; instead of &lt;code&gt;True&lt;/code&gt;, unless you passed the argument explicitly.&lt;/p&gt;

&lt;p&gt;The built-in safe set covers what most graphs actually persist: &lt;code&gt;datetime&lt;/code&gt; types, &lt;code&gt;uuid.UUID&lt;/code&gt;, &lt;code&gt;decimal.Decimal&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;frozenset&lt;/code&gt;, &lt;code&gt;deque&lt;/code&gt;, &lt;code&gt;ipaddress&lt;/code&gt; types, &lt;code&gt;pathlib&lt;/code&gt; paths, &lt;code&gt;zoneinfo.ZoneInfo&lt;/code&gt;, compiled regular expressions and selected LangGraph internal types. When strict mode is on and you compile a &lt;code&gt;StateGraph&lt;/code&gt;, LangGraph walks your state, input, output and context schemas plus node and branch input schemas and channel value types, and derives an allowlist automatically. It picks up Pydantic v1 and v2 models, dataclasses, enums, TypedDict field types and common typing constructs, plus a curated set of LangChain message classes.&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="c"&gt;# Patch the Python side&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; &lt;span class="s2"&gt;"langgraph&amp;gt;=1.0.10"&lt;/span&gt; &lt;span class="s2"&gt;"langgraph-checkpoint-sqlite&amp;gt;=3.0.1"&lt;/span&gt;

&lt;span class="c"&gt;# Patch the JavaScript side&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @langchain/langgraph-checkpoint-redis@^1.0.2
npm list @langchain/langgraph-checkpoint-redis

&lt;span class="c"&gt;# Turn on strict deserialisation in every non-local environment&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LANGGRAPH_STRICT_MSGPACK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Roll strict mode out in staging first and read the logs. The permissive default warns on every unregistered extension type it reconstructs, which gives you a free inventory of exactly what your graphs serialise before you start blocking anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two escape hatches that silently disable the fix
&lt;/h2&gt;

&lt;p&gt;Both are documented in the advisory, and both are easy to hit by accident.&lt;/p&gt;

&lt;p&gt;The first: allowlist enforcement is applied by the checkpointer, through a &lt;code&gt;with_allowlist(...)&lt;/code&gt; method. A checkpointer implementation that does not provide it skips enforcement and emits a warning. If you wrote your own saver, or you are using a community backend, strict mode may be doing nothing at all. Verify rather than assume.&lt;/p&gt;

&lt;p&gt;The second: if your application supplies a custom msgpack unpack hook via &lt;code&gt;ext_hook&lt;/code&gt;, that hook controls reconstruction and bypasses the default allowlist checks entirely. The advisory calls this an intentional escape hatch. It is also exactly the kind of code somebody adds to make one stubborn type round-trip, three sprints before the audit.&lt;/p&gt;

&lt;p&gt;A third failure mode is not in the advisory but shows up in practice: constructing serializers or checkpointers manually rather than letting &lt;code&gt;StateGraph.compile()&lt;/code&gt; wire them up. The derived allowlist only applies when LangGraph compiles the graph and the checkpointer supports propagation. Hand-built object graphs get the default policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection: what to look for in logs
&lt;/h2&gt;

&lt;p&gt;You cannot retroactively prove nothing happened, but you can look in three places.&lt;/p&gt;

&lt;p&gt;For the SQLite path, search application logs for filter keys containing SQL metacharacters, quotes, &lt;code&gt;json_extract&lt;/code&gt;, &lt;code&gt;UNION&lt;/code&gt; or comment markers, and for checkpoint searches that returned unusually large result sets. For the Redis path, look for filter values containing RediSearch syntax characters (&lt;code&gt;@&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;{&lt;/code&gt;, &lt;code&gt;}&lt;/code&gt;, &lt;code&gt;[&lt;/code&gt;, &lt;code&gt;]&lt;/code&gt;, backslash) and enable verbose Redis query logging so the executed queries are actually recoverable. Redis slow-query logs are useful here because injected queries tend to be structurally odd.&lt;/p&gt;

&lt;p&gt;For the deserialisation path, the permissive default's own warnings are the signal. Every reconstruction of an unregistered extension type gets logged. If you have those logs from before the patch, grep them for module names that are not in your application's dependency tree.&lt;/p&gt;

&lt;p&gt;At the infrastructure layer, treat the checkpoint store as integrity-sensitive. Restrict write access to the runtime itself, rotate credentials if compromise is suspected, and log every principal that has ever written to it. This is the same posture we argue for in &lt;a href="https://ecorpit.com/enterprise-ai-agent-governance-layers-2026/" rel="noopener noreferrer"&gt;enterprise AI agent governance layers&lt;/a&gt;: the agent's blast radius is the union of everything its credentials can reach, and the checkpoint store is inside that union.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the "moderate" rating is misleading
&lt;/h2&gt;

&lt;p&gt;CVE-2026-28277 scores 6.8 with an EPSS probability of 0.332%, which sits at the 56th percentile. Read alone, that is a patch-next-cycle number. Read as the second half of a chain that starts with a 7.3 SQL injection reachable from an HTTP parameter, it is not.&lt;/p&gt;

&lt;p&gt;This is a recurring pattern with agent frameworks rather than a LangGraph-specific failure. Check Point's conclusion was that classic vulnerability classes become more potent inside AI agent frameworks because those frameworks carry elevated access and trust. The framework holds provider API keys, database handles and tool credentials in one process. A bug class that would be a data-leak in a CRUD service becomes credential exfiltration in an agent runtime.&lt;/p&gt;

&lt;p&gt;Lotem Finkelstein, VP, Check Point Research, framed the broader shift in the firm's AI Security Report 2026: "The expertise barrier that separated capable attackers from the rest is disappearing, and defenders can no longer assume a human is setting the pace on the other side. The organizations that stay ahead will be the ones that govern how AI is used, secure the AI systems they now depend on, and defend at machine speed rather than human speed."&lt;/p&gt;

&lt;p&gt;The same report found that between October 2025 and May 2026, 87% to 93% of organisations experienced at least one high-risk AI interaction every month. Check Point's 2026 Cloud Security Report puts the governance gap in one figure: 77% of organisations have updated their cloud security strategy in response to AI, but only 26% say they have the architecture to enforce it, a 51-point spread between intent and capability.&lt;/p&gt;

&lt;p&gt;Check Point's own remediation guidance for this chain goes past the version bump: put authentication in front of self-hosted LangGraph servers, avoid long-lived static secrets, enforce network segmentation, treat AI agents as privileged identities, and apply least privilege to the agent's access footprint. That last point is the durable one. The framework you pick matters less than the credentials you hand it, which is the argument we made when comparing &lt;a href="https://ecorpit.com/ai-agent-framework-production-langgraph-crewai-microsoft-pydantic-2026/" rel="noopener noreferrer"&gt;AI agent frameworks for production&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this fits in your agent threat model
&lt;/h2&gt;

&lt;p&gt;Prompt injection gets the attention because it is novel. This chain is a reminder that the boring half of the attack surface is still there: an ORM-free f-string, a permissive deserialiser, an endpoint that trusts a dictionary from the client. Teams that have invested in &lt;a href="https://ecorpit.com/ai-agent-security-prompt-injection-guardrails-2026/" rel="noopener noreferrer"&gt;prompt injection guardrails for AI agents&lt;/a&gt; sometimes have zero coverage on the persistence layer beneath them, and an attacker with a choice will take the SQL injection every time.&lt;/p&gt;

&lt;p&gt;Three practical adjustments follow.&lt;/p&gt;

&lt;p&gt;Treat the checkpoint store as a trust boundary, not an implementation detail. Anything that can write to it can, in the worst case, execute in your runtime. That deserves the same review as a message queue an untrusted producer can publish to.&lt;/p&gt;

&lt;p&gt;Make filter construction server-side by contract. The agent server should build filter dictionaries from a validated session, never accept one from a request body. This single rule would have neutralised two of the three CVEs regardless of version.&lt;/p&gt;

&lt;p&gt;Pin and monitor the framework, not just the model. Model versions get change-managed carefully while &lt;code&gt;langgraph&lt;/code&gt; floats on a caret range. The same discipline that applies to &lt;a href="https://ecorpit.com/mcp-server-hardening-cves-configs-2026/" rel="noopener noreferrer"&gt;MCP server hardening&lt;/a&gt; applies here: agent-adjacent infrastructure needs a named owner and a patch SLA.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;For Indian teams, the compliance exposure is concrete rather than theoretical. Agent checkpoint state routinely contains names, contact details, order histories and support transcripts, all of which are personal data under the Digital Personal Data Protection Act 2023. The Act's substantive obligations tighten through 2026 ahead of hard enforcement in May 2027, and the Data Protection Board of India can impose penalties reaching ₹250 crore, roughly $26 million, for major violations.&lt;/p&gt;

&lt;p&gt;Two consequences follow for anyone running a self-hosted agent on Indian customer data. First, a checkpoint-table leak through CVE-2025-67644 is a personal-data breach, not just a bug, and your breach-notification clock is a legal one. Second, retention limits apply to checkpoints. Most teams never set a TTL on the checkpoint table, so a graph that ran once in March is still holding a full conversation transcript in August. Set retention, and document it, alongside the rest of the work in the &lt;a href="https://ecorpit.com/dpdp-act-engineering-playbook-indian-startups-2026/" rel="noopener noreferrer"&gt;DPDP Act engineering playbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The practical sequencing for an Indian engineering team is patch, then scope, then retain. Get to the fixed versions this week. Then determine whether any user-controlled string ever reached a filter key, because that answer decides whether you are writing a changelog entry or a breach assessment. Then put a retention policy on the store so the next incident has a smaller blast radius. For the wider picture of what production agents need before they touch customer data, see our guide to &lt;a href="https://ecorpit.com/enterprise-ai-agents-production-use-cases-2026/" rel="noopener noreferrer"&gt;enterprise AI agents in production&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which LangGraph versions fix these three CVEs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Upgrade &lt;code&gt;langgraph&lt;/code&gt; to 1.0.10 or later for the msgpack deserialisation issue, &lt;code&gt;langgraph-checkpoint-sqlite&lt;/code&gt; to 3.0.1 or later for the SQL injection, and &lt;code&gt;@langchain/langgraph-checkpoint-redis&lt;/code&gt; to 1.0.2 or later for the RediSearch query injection. Patch all three even if you believe only one backend is in use, because staging environments frequently differ from production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a PostgreSQL checkpointer safe from this chain?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL is not named in the three advisories, so it avoids the SQL injection and the RediSearch injection. It does not avoid CVE-2026-28277, because the unsafe msgpack decoder lives in the &lt;code&gt;langgraph&lt;/code&gt; package itself. Any deployment running version 1.0.9 or below still reconstructs Python objects from checkpoint bytes and needs the upgrade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does upgrading alone stop arbitrary object reconstruction?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. After patching, the default &lt;code&gt;allowed_msgpack_modules&lt;/code&gt; value is still &lt;code&gt;True&lt;/code&gt;, which reconstructs every extension type and only logs a warning. Set the environment variable &lt;code&gt;LANGGRAPH_STRICT_MSGPACK&lt;/code&gt; to true so the serializer defaults to strict, or pass an explicit allowlist. Test in staging first and read the warning logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How was the attack chain actually executed?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The attacker crafts a msgpack payload, then sends a malicious filter parameter to an endpoint reaching &lt;code&gt;get_state_history()&lt;/code&gt;. The SQL injection makes the query return a fabricated checkpoint row containing that payload. The application deserialises the row's BLOB, the unsafe decoder reconstructs the attacker's object, and code executes inside the agent runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is LangSmith Deployment affected by these vulnerabilities?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Check Point stated that LangChain's managed platform, LangSmith Deployment, is not affected, and the LangGraph maintainers said typical hosted configurations are designed to prevent the checkpoint-store tampering the threat model requires. The chain is exploitable in self-hosted deployments using the SQLite or Redis checkpointer with user-controlled filter input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can silently disable the msgpack allowlist?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two documented escape hatches. A checkpointer that does not implement &lt;code&gt;with_allowlist&lt;/code&gt; skips enforcement and only emits a warning, so custom or community savers may gain nothing from strict mode. Separately, an application-supplied &lt;code&gt;ext_hook&lt;/code&gt; takes control of reconstruction and bypasses the default allowlist checks entirely, which is intentional but weakens the protection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Were these flaws exploited in the wild?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The GitHub advisory for CVE-2026-28277 states there is no evidence of exploitation in the wild, and LangGraph is not aware of a practical exploitation path in existing deployments today. The EPSS score of 0.332% sits at the 56th percentile. Treat that as a reason to patch calmly, not as a reason to defer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does a checkpoint-table leak count as a breach under DPDP?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the checkpoint state contains personal data, and agent conversation state usually does, then unauthorised access to it is a personal-data breach under the Digital Personal Data Protection Act 2023. The Data Protection Board of India can impose penalties up to ₹250 crore for major violations, so scope the exposure before deciding it was only a bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT builds and hardens production AI agent systems for teams in India and abroad, and this is exactly the kind of work our senior engineering teams do: inventory the framework and checkpointer versions across every environment, trace which request paths reach a filter key, turn on strict deserialisation without breaking your graphs, and put retention and least-privilege controls on the state store. We are ISO 27001:2022 certified and CMMI Level 5 appraised, and we design applications aligned with DPDP requirements. If you are running self-hosted LangGraph and want a second pair of eyes on the persistence layer before your next audit, &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;contact us&lt;/a&gt; and we will scope a review.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/06/langgraph-flaw-chain-exposes-self.html" rel="noopener noreferrer"&gt;LangGraph Flaw Chain Exposes Self-Hosted AI Agents to Remote Code Execution&lt;/a&gt; - The Hacker News, 12 June 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/advisories/GHSA-g48c-2wqr-h844" rel="noopener noreferrer"&gt;CVE-2026-28277: LangGraph checkpoint loading has unsafe msgpack deserialization (GHSA-g48c-2wqr-h844)&lt;/a&gt; - GitHub Advisory Database, 5 March 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/langchain-ai/langgraph/security/advisories/GHSA-9rwj-6rc7-p77c" rel="noopener noreferrer"&gt;GHSA-9rwj-6rc7-p77c: LangGraph SQLite checkpointer SQL injection&lt;/a&gt; - langchain-ai/langgraph security advisories&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/langchain-ai/langgraphjs/security/advisories/GHSA-5mx2-w598-339m" rel="noopener noreferrer"&gt;GHSA-5mx2-w598-339m: RediSearch query injection in @langchain/langgraph-checkpoint-redis&lt;/a&gt; - langchain-ai/langgraphjs security advisories&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://advisories.gitlab.com/pypi/langgraph-checkpoint-sqlite/CVE-2025-67644/" rel="noopener noreferrer"&gt;CVE-2025-67644 advisory for langgraph-checkpoint-sqlite&lt;/a&gt; - GitLab Advisory Database&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://research.checkpoint.com/2026/from-sqli-to-rce-exploiting-langgraphs-checkpointer/" rel="noopener noreferrer"&gt;From SQLi to RCE: exploiting LangGraph's checkpointer&lt;/a&gt; - Check Point Research, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sentinelone.com/vulnerability-database/cve-2026-27022/" rel="noopener noreferrer"&gt;CVE-2026-27022: LangGraph Redis checkpoint query injection&lt;/a&gt; - SentinelOne Vulnerability Database, 27 February 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/langchain-ai/langgraphjs/pull/1943" rel="noopener noreferrer"&gt;Pull request 1943: escape RediSearch tag values in the Redis checkpointer&lt;/a&gt; - langchain-ai/langgraphjs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nvd.nist.gov/vuln/detail/CVE-2026-28277" rel="noopener noreferrer"&gt;NVD entry for CVE-2026-28277&lt;/a&gt; - National Vulnerability Database&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cwe.mitre.org/data/definitions/502.html" rel="noopener noreferrer"&gt;CWE-502: Deserialization of Untrusted Data&lt;/a&gt; - MITRE&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.helpnetsecurity.com/2026/07/15/check-point-ai-security-report-2026/" rel="noopener noreferrer"&gt;AI used to help plan the break-in, now it's doing the break-in&lt;/a&gt; - Help Net Security, 15 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.checkpoint.com/press-releases/ai-adoption-creates-critical-cloud-security-gaps-for-enterprises-new-check-point-report-shows/" rel="noopener noreferrer"&gt;AI adoption creates critical cloud security gaps for enterprises&lt;/a&gt; - Check Point Software press release, 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.india-briefing.com/news/india-dpdp-compliance-timeline-enforcement-2026-27-44740.html/" rel="noopener noreferrer"&gt;India's DPDP timeline: critical compliance deadlines for 2026-27&lt;/a&gt; - India Briefing, 11 May 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.unite.ai/check-points-2026-cloud-security-report-securing-the-ai-transformation-warns-enterprise-security-is-falling-behind-ai-adoption/" rel="noopener noreferrer"&gt;Check Point's 2026 Cloud Security Report: Securing the AI Transformation&lt;/a&gt; - Unite.AI summary of the Check Point and Cybersecurity Insiders survey, 26 May 2026&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last updated: 5 August 2026.&lt;/p&gt;

</description>
      <category>langgraph</category>
    </item>
    <item>
      <title>26 days to the Play Store API 36 cutoff: a 3-week migration plan for Indian app teams</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 11:04:59 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/26-days-to-the-play-store-api-36-cutoff-a-3-week-migration-plan-for-indian-app-teams-31ak</link>
      <guid>https://dev.to/mr_manushukla/26-days-to-the-play-store-api-36-cutoff-a-3-week-migration-plan-for-indian-app-teams-31ak</guid>
      <description>&lt;h1&gt;
  
  
  26 days to the Play Store API 36 cutoff: a 3-week migration plan for Indian app teams
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; From 31 August 2026, Google Play will not accept new apps or app updates that target below Android 16 (API level 36). That is 26 days from this article's 5 August 2026 date. The Play Console Help page is explicit: on that date, both new apps and app updates must set &lt;code&gt;targetSdkVersion&lt;/code&gt; to 36 or higher, with Wear OS and Android Automotive OS held to API 35 and Android TV and Android XR to API 34. If you miss it, you cannot ship an update, but you are not permanently locked out: Google will let you request an extension to 1 November 2026 through the Policy status page in Play Console, and existing installs keep working. The trap is treating this as a one-line manifest change. Targeting Android 16 turns on real behaviour changes, edge-to-edge enforcement, adaptive-layout rules on screens 600dp and wider, stricter JobScheduler quotas, and a dropped &lt;code&gt;elegantTextHeight&lt;/code&gt; opt-out, on top of the separate 16 KB native-page-size requirement that has applied to API 35+ builds since 1 November 2025. For an Indian team with a live app and other roadmap work, the realistic cost is 2 to 3 weeks of focused engineering, and it collapses fast if native SDKs are involved. This article lays out what breaks, a three-week plan, and how eCorpIT runs this as a fixed-scope engagement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the deadline actually says
&lt;/h2&gt;

&lt;p&gt;The distinction that catches teams out is new app versus app update versus existing app. The Play Console Help page defines all three, and the rule differs for each.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your situation&lt;/th&gt;
&lt;th&gt;Requirement on 31 August 2026&lt;/th&gt;
&lt;th&gt;If you miss it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Submitting a brand new app&lt;/td&gt;
&lt;td&gt;Must target API 36&lt;/td&gt;
&lt;td&gt;Submission rejected in Play Console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Submitting an update to a live app&lt;/td&gt;
&lt;td&gt;Must target API 36&lt;/td&gt;
&lt;td&gt;Update rejected; you cannot ship&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live app you will not update&lt;/td&gt;
&lt;td&gt;Must already target API 35 to stay discoverable to new users on newer devices&lt;/td&gt;
&lt;td&gt;Stops appearing for new users on Android OS above your target; existing users keep it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the middle row twice. The most common shape for a working product is a live app you update regularly. From 31 August, the next update you try to push is blocked unless the build targets API 36. Every bug fix, every feature, every security patch goes through that gate.&lt;/p&gt;

&lt;p&gt;The extension is real but limited. Google states you can request an extension to 1 November 2026, and the form appears on the Policy status page in Play Console for apps flagged as non-compliant, reached via a policy warning on that app. It buys nine weeks, not a reprieve. Use it to finish the work, not to avoid it.&lt;/p&gt;

&lt;p&gt;One reassurance worth stating plainly, because it calms the room: users who already installed your app are not affected. Google's own FAQ says previously installed users can still discover, reinstall and use the app on any Android version it supports. The deadline governs distribution to new users on newer devices, and your ability to ship updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is not a one-line change
&lt;/h2&gt;

&lt;p&gt;Bumping &lt;code&gt;targetSdkVersion&lt;/code&gt; to 36 is one line in &lt;code&gt;build.gradle&lt;/code&gt;. The work is everything that line switches on. Here are the behaviour changes that most often break a real app, all from the Android 16 behaviour-changes documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edge-to-edge is enforced.&lt;/strong&gt; Apps targeting Android 16 can no longer opt out of drawing edge-to-edge. Your content extends behind the status and navigation bars unless you handle window insets. If your app has custom toolbars, bottom bars or full-screen media, expect visible overlap until you apply insets correctly. This is the single most common visual regression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adaptive layout rules apply on large screens.&lt;/strong&gt; For apps targeting API 36, orientation, resizability and aspect-ratio restrictions are ignored on displays with a smallest width of 600dp or more, so the app fills the whole window regardless of a &lt;code&gt;screenOrientation&lt;/code&gt; lock. Portrait-only apps that assumed a fixed orientation on tablets and foldables will now resize, and layouts that were never tested wide will show their seams. For the large and growing Indian tablet and foldable base, this is not a corner case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JobScheduler quotas tighten.&lt;/strong&gt; Android 16 enforces JobScheduler quotas more strictly. Background jobs that ran comfortably before can be throttled, which surfaces as delayed syncs, missed uploads or stalled background refresh. Apps that lean on background work, most commerce, logistics and messaging apps do, need to re-test their job scheduling under the new limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;elegantTextHeight&lt;/code&gt; opt-out is gone.&lt;/strong&gt; Targeting Android 16 makes the system ignore an &lt;code&gt;elegantTextHeight="false"&lt;/code&gt; setting, to give correct spacing for scripts including Tamil, Kannada, Malayalam, Telugu, Gujarati and Odia. For Indian-language apps this is mostly an improvement, but it changes line height and can break tight custom layouts, so it needs a visual pass in every supported script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access to Android internals may break.&lt;/strong&gt; If the app or an SDK reaches into Android internals through reflection or JNI, Android 16 may block it. This is where old dependencies bite.&lt;/p&gt;

&lt;p&gt;Separately from the target-API rules, the 16 KB native page-size requirement has applied since 1 November 2025 to apps targeting API 35 and above on 64-bit devices. If your app or any SDK ships native &lt;code&gt;.so&lt;/code&gt; libraries, they must be rebuilt to support 16 KB memory pages. Pure Kotlin or Java apps are generally unaffected; anything with native code, and that includes many analytics, media, maps and payment SDKs, is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the time actually goes
&lt;/h2&gt;

&lt;p&gt;The honest estimate depends almost entirely on one question: does your app ship native code, directly or through an SDK?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;App profile&lt;/th&gt;
&lt;th&gt;Realistic effort&lt;/th&gt;
&lt;th&gt;Main risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pure Kotlin/Java, few SDKs&lt;/td&gt;
&lt;td&gt;3 to 5 working days&lt;/td&gt;
&lt;td&gt;Edge-to-edge insets, large-screen layout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kotlin/Java with several third-party SDKs&lt;/td&gt;
&lt;td&gt;1 to 2 weeks&lt;/td&gt;
&lt;td&gt;An SDK not yet API-36 or 16 KB ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native code or older SDKs (maps, media, payments)&lt;/td&gt;
&lt;td&gt;2 to 3 weeks&lt;/td&gt;
&lt;td&gt;Rebuilding &lt;code&gt;.so&lt;/code&gt; for 16 KB; SDK upgrades&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React Native or Flutter&lt;/td&gt;
&lt;td&gt;1 to 2 weeks&lt;/td&gt;
&lt;td&gt;Plugin and toolchain updates, then the same behaviour changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The line that blows up estimates is a dependency you do not control. If a payment, chat or analytics SDK has not shipped an API-36-ready and 16 KB-ready build, you wait on their release or replace them, and that is outside your team's velocity. Finding those blockers in week one, not week three, is the whole game.&lt;/p&gt;

&lt;p&gt;Cross-platform teams do not escape this. A React Native or Flutter app still produces an Android build with a target API level, and still hits edge-to-edge, adaptive layout and native-page-size requirements through its native modules and plugins. If you are weighing frameworks for a rebuild rather than a migration, our comparison of &lt;a href="https://ecorpit.com/expo-vs-react-native/" rel="noopener noreferrer"&gt;Expo versus bare React Native&lt;/a&gt; and of &lt;a href="https://ecorpit.com/jetpack-compose-vs-flutter/" rel="noopener noreferrer"&gt;Jetpack Compose versus Flutter&lt;/a&gt; covers the trade-offs.&lt;/p&gt;

&lt;h2&gt;
  
  
  A three-week plan that finishes before the deadline
&lt;/h2&gt;

&lt;p&gt;This is the sequence we run. It front-loads discovery so the unknowns surface while there is still time to act on them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 1 — audit and unblock.&lt;/strong&gt; Set &lt;code&gt;targetSdkVersion 36&lt;/code&gt; in a branch and let the build tell you the truth. Inventory every dependency and native &lt;code&gt;.so&lt;/code&gt; file, and check each SDK for an API-36-ready and 16 KB-ready release. File the upgrades or replacements now, because those have the longest lead time. Run the app on a 16 KB-page-size emulator image and on a 600dp+ device or foldable to see the layout changes immediately. By the end of week one you should have a written list of blockers with an owner against each.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 2 — fix behaviour changes.&lt;/strong&gt; Apply window insets so edge-to-edge renders correctly across every screen. Fix large-screen layouts where the orientation lock no longer holds. Re-test background jobs against the tighter JobScheduler quotas and adjust scheduling. Do a visual pass in each supported Indian-language script for the &lt;code&gt;elegantTextHeight&lt;/code&gt; change. Rebuild native libraries for 16 KB pages and integrate the upgraded SDKs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Week 3 — test, stage, submit.&lt;/strong&gt; Run the full regression suite plus device-matrix testing across your real Android version and screen-size spread. Push to a Play Console internal or closed track first to confirm the store accepts the API-36 build and nothing regressed in vitals. Then promote to production. Keeping an eye on crash and ANR rates after a target-SDK bump matters, because behaviour changes surface as new crashes in the field; our &lt;a href="https://ecorpit.com/ecorpit-android-vitals-anr-crash-remediation-service-india-2026/" rel="noopener noreferrer"&gt;Android vitals ANR and crash remediation work&lt;/a&gt; exists for exactly that post-migration window.&lt;/p&gt;

&lt;p&gt;Starting this week, three weeks lands you at roughly 26 August, inside the 31 August deadline with a few days of buffer. Starting in the last week means relying on the 1 November extension, which is a worse place to negotiate from.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;Two things make this sharper for Indian teams. First, the device mix here skews toward a wide range of Android versions and a fast-growing tablet and foldable base, so the adaptive-layout and large-screen changes hit a larger share of real users than they would in a single-flagship market. Test on mid-range and large-screen devices, not just a recent flagship.&lt;/p&gt;

&lt;p&gt;Second, the Indian-language rendering change is a feature, not just a risk, if you plan for it. The &lt;code&gt;elegantTextHeight&lt;/code&gt; behaviour improves spacing for major Indian scripts, so an app that supports Hindi, Tamil, Telugu, Kannada, Malayalam, Gujarati or Odia should verify each one looks right and can market the improvement rather than merely absorbing the layout shift.&lt;/p&gt;

&lt;p&gt;Where personal data is involved, design and test the update against Digital Personal Data Protection Act 2023 expectations as you would any release; the target-SDK change does not alter your obligations, but a rushed migration is a common moment for a permissions or data-handling regression to slip in.&lt;/p&gt;

&lt;h2&gt;
  
  
  How this compares to doing nothing
&lt;/h2&gt;

&lt;p&gt;For a team genuinely weighing whether to act, the options are narrow.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;th&gt;When it makes sense&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Migrate to API 36 by 31 August&lt;/td&gt;
&lt;td&gt;Keep shipping updates normally&lt;/td&gt;
&lt;td&gt;Any actively developed app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request the extension to 1 November&lt;/td&gt;
&lt;td&gt;Nine more weeks, then migrate anyway&lt;/td&gt;
&lt;td&gt;You need updates live but cannot finish in 26 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Do nothing, app already targets API 35&lt;/td&gt;
&lt;td&gt;Stays discoverable to new users; you still cannot ship an update after 31 August&lt;/td&gt;
&lt;td&gt;A frozen app you will not touch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Do nothing, app targets below API 35&lt;/td&gt;
&lt;td&gt;Drops from discovery for new users on newer devices&lt;/td&gt;
&lt;td&gt;Effectively retiring the app&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is no version of "keep shipping updates without migrating." That is the point of the deadline.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT is a senior-led mobile engineering organisation in Gurugram, founded in 2021, CMMI Level 5 and ISO 27001:2022 certified, and a Google partner. We run target-SDK migrations as a fixed-scope engagement: a week-one audit that surfaces every SDK and native-library blocker, the behaviour-change fixes across edge-to-edge, adaptive layout, JobScheduler and 16 KB pages, and a staged Play Console rollout with vitals monitoring afterwards. It suits Indian product owners and mobile leads whose app still targets API 35 or lower and who would rather not pull their own roadmap apart 26 days before the cutoff. For the broader engineering picture, see our &lt;a href="https://ecorpit.com/enterprise-mobile-app-development-guide/" rel="noopener noreferrer"&gt;enterprise mobile app development guide&lt;/a&gt;; to scope a migration, reach us at &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;/contact-us/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What exactly changes on 31 August 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From that date, Google Play stops accepting new apps and app updates that target below Android 16 (API level 36). Wear OS and Android Automotive OS must target API 35, and Android TV and Android XR must target API 34. Existing installed apps keep working, and you can request an extension to 1 November 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is my app removed from the Play Store if I miss the deadline?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Your existing users keep the app and can reinstall and use it. What you lose is the ability to submit updates, and if your app targets below API 35 it also stops being discoverable to new users on Android versions newer than your target. Apps already on API 35 stay discoverable but still cannot ship updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I still get more time after 31 August?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Google provides an extension to 1 November 2026 for apps flagged as non-compliant. The extension form appears on the Policy status page in Play Console, reached through the policy warning on the affected app. It gives nine extra weeks to complete the migration, not a permanent exemption from the requirement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why can't I just change one line in the manifest?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because setting targetSdkVersion to 36 activates Android 16's behaviour changes. Edge-to-edge rendering is enforced, orientation and aspect-ratio locks are ignored on 600dp-plus screens, JobScheduler quotas tighten, and the elegantTextHeight opt-out is dropped. Each can break a real screen, so the change needs testing, not just a version bump.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the 16 KB page size requirement?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since 1 November 2025, apps targeting API 35 or higher on 64-bit devices must support 16 KB memory pages. If your app or any SDK ships native .so libraries, those must be rebuilt for 16 KB pages. Pure Kotlin or Java apps are generally unaffected, but native code and many third-party SDKs are, so audit your dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does the migration take?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a pure Kotlin or Java app with few SDKs, three to five working days. With several third-party SDKs, one to two weeks. With native code or older maps, media or payment SDKs, two to three weeks, mostly spent rebuilding native libraries and upgrading dependencies. The estimate hinges on whether any SDK is not yet API-36 and 16 KB ready.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this affect React Native or Flutter apps?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. A cross-platform app still produces an Android build with a target API level and still hits edge-to-edge, adaptive-layout and 16 KB requirements through its native modules or plugins. You update the framework toolchain and plugins first, then handle the same Android 16 behaviour changes as a native app would.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should Indian teams test that others might skip?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Test on a wide range of Android versions and on mid-range and large-screen devices, because India's device mix and its growing tablet and foldable base make the adaptive-layout changes hit more users. Verify each supported Indian-language script, since the elegantTextHeight change alters text spacing for Tamil, Telugu, Kannada, Malayalam, Gujarati, Odia and others.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/googleplay/android-developer/answer/11926878?hl=en" rel="noopener noreferrer"&gt;Target API level requirements for Google Play apps&lt;/a&gt; - Play Console Help&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/about-us/versions/16/behavior-changes-16" rel="noopener noreferrer"&gt;Behavior changes: Apps targeting Android 16 or higher&lt;/a&gt; - Android Developers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://android-developers.googleblog.com/2025/06/android-16-is-here.html" rel="noopener noreferrer"&gt;Android 16 is here&lt;/a&gt; - Android Developers Blog&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://android-developers.googleblog.com/2025/01/orientation-and-resizability-changes-in-android-16.html" rel="noopener noreferrer"&gt;The future is adaptive: changes to orientation and resizability APIs in Android 16&lt;/a&gt; - Android Developers Blog&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/develop/ui/compose/layouts/adaptive/app-orientation-aspect-ratio-resizability" rel="noopener noreferrer"&gt;App orientation, aspect ratio, and resizability&lt;/a&gt; - Android Developers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/distribute/best-practices/develop/target-sdk.html" rel="noopener noreferrer"&gt;Migrate to target SDK best practices&lt;/a&gt; - Android Developers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/googleplay/android-developer/answer/17134731" rel="noopener noreferrer"&gt;Policy announcement: July 15, 2026&lt;/a&gt; - Play Console Help&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/dainyjose/google-play-requires-android-16-api-level-36-by-august-31-2026-react-native-migration-guide-1d51"&gt;Google Play Requires Android 16 (API Level 36) by August 31, 2026 — React Native Migration Guide&lt;/a&gt; - DEV Community&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://proandroiddev.com/android-16-migration-hacks-the-developers-survival-guide-81c3722bb122" rel="noopener noreferrer"&gt;Android 16 Migration Hacks: The Developer's Survival Guide&lt;/a&gt; - ProAndroidDev&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://median.co/blog/google-plays-target-api-level-requirement-for-android-apps" rel="noopener noreferrer"&gt;Google Play target API requirements for Android apps (2026)&lt;/a&gt; - Median.co&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last updated: 5 August 2026.&lt;/p&gt;

</description>
      <category>targetapi36</category>
      <category>android16</category>
      <category>googleplay</category>
      <category>appmigration</category>
    </item>
    <item>
      <title>CVE-2026-34486: one moved line turned Tomcat's cluster encryption into RCE</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 10:59:22 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/cve-2026-34486-one-moved-line-turned-tomcats-cluster-encryption-into-rce-9g6</link>
      <guid>https://dev.to/mr_manushukla/cve-2026-34486-one-moved-line-turned-tomcats-cluster-encryption-into-rce-9g6</guid>
      <description>&lt;h1&gt;
  
  
  CVE-2026-34486: one moved line turned Tomcat's cluster encryption into RCE
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; CVE-2026-34486 is a fail-open regression in Apache Tomcat's Tribes clustering, disclosed on 9 April 2026 and added to CISA's Known Exploited Vulnerabilities catalog on 4 August 2026 at CVSS 7.5. The bug lives in &lt;code&gt;EncryptInterceptor&lt;/code&gt;, the component operators enable specifically to encrypt cluster traffic. A single line, &lt;code&gt;super.messageReceived(msg)&lt;/code&gt;, was moved outside its try/catch block during the 13 March 2026 fix for a separate padding-oracle bug (CVE-2026-29146). After that move, a message that fails to decrypt is no longer dropped: the original attacker-controlled bytes are forwarded up the chain to &lt;code&gt;XByteBuffer.deserialize()&lt;/code&gt;, a bare &lt;code&gt;ObjectInputStream.readObject()&lt;/code&gt; with no &lt;code&gt;ObjectInputFilter&lt;/code&gt;. Any host that can reach the Tribes receiver, TCP port 4000 by default, can send a serialized Java object; with a gadget library on the classpath, that is unauthenticated remote code execution. Affected versions are exactly three: 11.0.20, 10.1.53 and 9.0.116. Fixed releases 11.0.21, 10.1.54 and 9.0.117 shipped between 2 and 4 April 2026. Tomcat 8.5.x does not have &lt;code&gt;EncryptInterceptor&lt;/code&gt; and is not affected. The Hacker News reported on 5 August 2026 that exploitation of CVE-2026-34486 was tied to an autonomous AI-driven campaign that Palo Alto Networks Unit 42 attributes to an actor operating as knaithe. This guide shows how to tell whether you are exposed, what to patch, and how to harden the deserialization sink even after you patch.&lt;/p&gt;

&lt;p&gt;This is a developer and infrastructure guide, current as of 5 August 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this one is worse than a normal Tomcat CVE
&lt;/h2&gt;

&lt;p&gt;Most Tomcat advisories affect a feature you can reason about from the outside. This one has three properties that make it nastier.&lt;/p&gt;

&lt;p&gt;First, it only bites people who did the secure thing. &lt;code&gt;EncryptInterceptor&lt;/code&gt; is opt-in. You add it because you want cluster replication traffic encrypted with a pre-shared key. The regression is in the receive path of that exact component, so the population at risk is the subset of operators who already cared about cluster security.&lt;/p&gt;

&lt;p&gt;Second, the vulnerable window is narrow and specific. Exactly three point releases are affected, all shipped in a two-week window in March 2026. If you upgraded Tomcat during that window and pinned, you may be sitting on a vulnerable build without ever having touched the clustering config again.&lt;/p&gt;

&lt;p&gt;Third, the sink is Java deserialization, which converts "you can send bytes to a port" into "you can run code" whenever a usable gadget class is on the classpath. Spring, Hibernate and many common frameworks pull in transitive dependencies that have historically shipped gadget classes. You do not have to have added &lt;code&gt;commons-collections&lt;/code&gt; yourself for it to be reachable.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Tribes clustering works, in three sentences
&lt;/h2&gt;

&lt;p&gt;Tomcat's Tribes framework replicates HTTP session state across cluster nodes. When a session changes on one node, the change is serialized and broadcast over TCP to the others, and the receiver listens on port 4000 by default, bound to the primary network interface rather than localhost. The wire envelope has a fixed 7-byte header (&lt;code&gt;FLT2002&lt;/code&gt;), a length, the payload and a 7-byte footer, with no cryptographic protection or authentication on the framing itself.&lt;/p&gt;

&lt;p&gt;That last clause is the precondition for everything below. Any host that can open a TCP connection to the receiver can submit a well-formed Tribes message. &lt;code&gt;EncryptInterceptor&lt;/code&gt; was the gate that was supposed to make the contents safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-line regression, shown
&lt;/h2&gt;

&lt;p&gt;Striga, the firm that found and reported the bug, published the before-and-after. In Tomcat 11.0.18, &lt;code&gt;EncryptInterceptor.messageReceived()&lt;/code&gt; calls &lt;code&gt;super.messageReceived(msg)&lt;/code&gt; inside the try block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;messageReceived&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChannelMessage&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getBytes&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encryptionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;decrypt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;XByteBuffer&lt;/span&gt; &lt;span class="n"&gt;xbb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;xbb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;xbb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;messageReceived&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GeneralSecurityException&lt;/span&gt; &lt;span class="n"&gt;gse&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"encryptInterceptor.decrypt.failed"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;gse&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;decrypt()&lt;/code&gt; throws, control jumps to the catch, the error is logged, and the method returns. The message is dropped. That is fail-closed.&lt;/p&gt;

&lt;p&gt;The 13 March 2026 fix for CVE-2026-29146 restructured the encryption manager to support &lt;code&gt;AES/GCM/NoPadding&lt;/code&gt; and move away from the padding-oracle-prone &lt;code&gt;AES/CBC/PKCS5Padding&lt;/code&gt;. In the process, the call moved one line down, outside the catch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;messageReceived&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChannelMessage&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getBytes&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encryptionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;decrypt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;XByteBuffer&lt;/span&gt; &lt;span class="n"&gt;xbb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;xbb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;xbb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GeneralSecurityException&lt;/span&gt; &lt;span class="n"&gt;gse&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"encryptInterceptor.decrypt.failed"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;gse&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;messageReceived&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;super.messageReceived(msg)&lt;/code&gt; runs unconditionally. On a decrypt failure the catch logs the error, then the original, unmodified, attacker-controlled bytes go up the interceptor chain anyway. They reach &lt;code&gt;GroupChannel.messageReceived()&lt;/code&gt;, which calls &lt;code&gt;XByteBuffer.deserialize()&lt;/code&gt;, which creates a plain &lt;code&gt;ObjectInputStream&lt;/code&gt; with no class filter and calls &lt;code&gt;readObject()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The send path in the same class throws &lt;code&gt;ChannelException&lt;/code&gt; on encryption failure, so it stays fail-closed. The asymmetry, fail-closed on send and fail-open on receive, is accidental, and it is the whole vulnerability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The attack chain, at the level you need to defend it
&lt;/h2&gt;

&lt;p&gt;You do not need to write the exploit to defend against it, but you should understand the five steps so your controls map to them.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Where you can break it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Reach the port&lt;/td&gt;
&lt;td&gt;Attacker opens TCP to the receiver (default 4000)&lt;/td&gt;
&lt;td&gt;Network segmentation, firewall, NetworkPolicy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Frame a message&lt;/td&gt;
&lt;td&gt;Attacker builds a raw Tribes envelope with a fake member address; no auth on the framing&lt;/td&gt;
&lt;td&gt;Not defensible at this layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Fail decryption&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;EncryptInterceptor&lt;/code&gt; throws, logs "Failed to decrypt message"&lt;/td&gt;
&lt;td&gt;Patch restores the drop here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Forward the bytes&lt;/td&gt;
&lt;td&gt;Regression forwards attacker bytes to &lt;code&gt;XByteBuffer.deserialize()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Patch; and &lt;code&gt;ObjectInputFilter&lt;/code&gt; blocks the class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Deserialize a gadget&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ObjectInputStream.readObject()&lt;/code&gt; runs a gadget chain to &lt;code&gt;Runtime.exec()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Remove gadget libraries; JVM-wide deserialization filter&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The single SEVERE log line that Striga observed is worth memorising, because it is what a defender sees on a real attempt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SEVERE [Tribes-Task-Receiver[Catalina-Channel]-1]
  org.apache.catalina.tribes.group.interceptors.EncryptInterceptor.messageReceived
  Failed to decrypt message
    javax.crypto.AEADBadTagException: Tag mismatch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No deserialization error follows it. On a vulnerable node the gadget executes silently after that line. So a &lt;code&gt;Failed to decrypt message&lt;/code&gt; entry that correlates with an unexpected inbound connection to port 4000 is not noise, it is your incident.&lt;/p&gt;

&lt;p&gt;On JDK 8u72 and later the classic CommonsCollections1 and CC3 chains are broken, but CC6 uses &lt;code&gt;HashSet&lt;/code&gt; as its entry point and works on JDK 17 and 21. Modern runtime does not save you here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step one: find out if you are exposed
&lt;/h2&gt;

&lt;p&gt;Run these three checks in order. You are only at risk if all three are true: an affected version, &lt;code&gt;EncryptInterceptor&lt;/code&gt; configured, and the receiver reachable beyond your trusted cluster members.&lt;/p&gt;

&lt;p&gt;Check the running version:&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="nv"&gt;$CATALINA_HOME&lt;/span&gt;/bin/version.sh | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Server number"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it reads 11.0.20, 10.1.53 or 9.0.116, you are on an affected build. Anything at or above 11.0.21 / 10.1.54 / 9.0.117 is fixed. Anything below the affected builds (for example 11.0.18) never had the regression. Tomcat 8.5.x is not affected at all.&lt;/p&gt;

&lt;p&gt;Check whether &lt;code&gt;EncryptInterceptor&lt;/code&gt; is actually in the channel. It lives in &lt;code&gt;server.xml&lt;/code&gt; (or a context's cluster config):&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="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s2"&gt;"EncryptInterceptor"&lt;/span&gt; &lt;span class="nv"&gt;$CATALINA_HOME&lt;/span&gt;/conf/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No match means the vulnerable code path is not in your interceptor chain, and this CVE does not apply to you even on an affected version. A match means you are in scope.&lt;/p&gt;

&lt;p&gt;Check whether the receiver port is listening and on which interface. The default is 4000, but read the &lt;code&gt;Receiver&lt;/code&gt; element's &lt;code&gt;port&lt;/code&gt; attribute to be sure:&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="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s2"&gt;"Receiver"&lt;/span&gt; &lt;span class="nv"&gt;$CATALINA_HOME&lt;/span&gt;/conf/server.xml
ss &lt;span class="nt"&gt;-ltnp&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;':4000|:400[0-9]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that socket is bound to &lt;code&gt;0.0.0.0&lt;/code&gt; or a routable address rather than a private cluster-only interface, treat it as reachable and move fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step two: patch to the fixed release
&lt;/h2&gt;

&lt;p&gt;The fix restores fail-closed behaviour by putting &lt;code&gt;super.messageReceived(msg)&lt;/code&gt; back inside the try block. Upgrade within your branch:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Branch&lt;/th&gt;
&lt;th&gt;Affected build&lt;/th&gt;
&lt;th&gt;Fixed build&lt;/th&gt;
&lt;th&gt;Fixed release date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;11.0.x&lt;/td&gt;
&lt;td&gt;11.0.20&lt;/td&gt;
&lt;td&gt;11.0.21&lt;/td&gt;
&lt;td&gt;4 April 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10.1.x&lt;/td&gt;
&lt;td&gt;10.1.53&lt;/td&gt;
&lt;td&gt;10.1.54&lt;/td&gt;
&lt;td&gt;2 April 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9.0.x&lt;/td&gt;
&lt;td&gt;9.0.116&lt;/td&gt;
&lt;td&gt;9.0.117&lt;/td&gt;
&lt;td&gt;3 April 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8.5.x&lt;/td&gt;
&lt;td&gt;not affected&lt;/td&gt;
&lt;td&gt;not applicable&lt;/td&gt;
&lt;td&gt;component absent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are minor patch upgrades within a branch, so for most deployments this is a binary swap and a restart, not a migration. Do it first. The hardening below is defence in depth, not a substitute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step three: harden the deserialization sink anyway
&lt;/h2&gt;

&lt;p&gt;Patching closes this specific regression. It does not change the underlying design fact that a decrypted, trusted Tribes message still lands in a &lt;code&gt;readObject()&lt;/code&gt; with no filter. A future bug in the same path would land in the same sink. Two durable controls are worth adding.&lt;/p&gt;

&lt;p&gt;Set a JVM-wide deserialization filter so untrusted classes cannot instantiate even if bytes reach &lt;code&gt;ObjectInputStream&lt;/code&gt;. From JDK 9 onward, &lt;code&gt;jdk.serialFilter&lt;/code&gt; accepts an allow and deny pattern. A blunt but effective starting point blocks the common gadget packages and rejects anything not on an allowlist:&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="c"&gt;# In setenv.sh&lt;/span&gt;
&lt;span class="nv"&gt;JAVA_OPTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$JAVA_OPTS&lt;/span&gt;&lt;span class="s2"&gt; -Djdk.serialFilter=!org.apache.commons.collections.functors.*;&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
!org.apache.commons.collections4.functors.*;&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
!org.codehaus.groovy.runtime.*;&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
!org.springframework.beans.factory.ObjectFactory;&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
!com.sun.org.apache.xalan.**;maxdepth=20;maxrefs=1000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test this against your own replication traffic in staging first, because an over-tight filter will break legitimate session objects. The goal is to deny known gadget entry points while allowing your own serialized session classes.&lt;/p&gt;

&lt;p&gt;Remove gadget libraries you do not need. If &lt;code&gt;commons-collections-3.1.jar&lt;/code&gt; is sitting in &lt;code&gt;$CATALINA_HOME/lib/&lt;/code&gt; and nothing you run needs it, delete it. Inventory the classpath for the usual suspects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nv"&gt;$CATALINA_HOME&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.jar"&lt;/span&gt; | xargs &lt;span class="nt"&gt;-I&lt;/span&gt;&lt;span class="o"&gt;{}&lt;/span&gt; sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'unzip -l "{}" 2&amp;gt;/dev/null | grep -qE "InvokerTransformer|TemplatesImpl" &amp;amp;&amp;amp; echo "{}"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A hit does not mean you are exploitable, but it tells you which library provides the gadget, so you can decide whether it belongs there.&lt;/p&gt;

&lt;p&gt;Bind the receiver to a private interface and firewall the port. The receiver should never be reachable from outside the cluster. Set the &lt;code&gt;Receiver&lt;/code&gt; &lt;code&gt;address&lt;/code&gt; to a dedicated cluster interface, and restrict port 4000 to peer nodes with a host firewall or security group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Receiver&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"org.apache.catalina.tribes.transport.nio.NioReceiver"&lt;/span&gt;
          &lt;span class="na"&gt;address=&lt;/span&gt;&lt;span class="s"&gt;"10.0.10.5"&lt;/span&gt;
          &lt;span class="na"&gt;port=&lt;/span&gt;&lt;span class="s"&gt;"4000"&lt;/span&gt;
          &lt;span class="na"&gt;selectorTimeout=&lt;/span&gt;&lt;span class="s"&gt;"5000"&lt;/span&gt;
          &lt;span class="na"&gt;maxThreads=&lt;/span&gt;&lt;span class="s"&gt;"6"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Kubernetes trap
&lt;/h2&gt;

&lt;p&gt;In a Kubernetes deployment without a NetworkPolicy, every pod in the same namespace can reach port 4000 on every other pod. That turns a design assumption ("only trusted cluster members reach the receiver") into a false one, because the trust boundary is now the whole namespace, including any pod an attacker lands in first.&lt;/p&gt;

&lt;p&gt;If you run Tomcat clustering in Kubernetes, a default-deny NetworkPolicy that only permits port 4000 between the cluster's own pods is not optional hardening, it is the control that makes the receiver's trust assumption true again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tomcat-tribes-restrict&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tomcat-cluster&lt;/span&gt;
  &lt;span class="na"&gt;policyTypes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tomcat-cluster&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Is it actually being exploited
&lt;/h2&gt;

&lt;p&gt;The honest answer changed over the life of this CVE, and both readings are worth stating.&lt;/p&gt;

&lt;p&gt;When SOCRadar wrote it up in April 2026, there was no confirmed in-the-wild exploitation: no KEV entry, no vendor statement, no incident reporting tied directly to CVE-2026-34486. The reasonable posture then was "treat exposed receivers as urgent regardless."&lt;/p&gt;

&lt;p&gt;That posture is now backed by evidence. CISA added CVE-2026-34486 to the KEV catalog on 4 August 2026, which by definition means CISA has reliable evidence of active exploitation. The Hacker News reported the same day that the exploitation is attributed to an autonomous AI-enabled campaign that Palo Alto Networks Unit 42 links to a Chinese-speaking actor operating as knaithe and KnYuan, which used the DeepSeek model through the Hermes agent framework to scan and attack internet-exposed devices, targeting over 460 hosts across a mix of automated and manual techniques. US federal civilian agencies were given until 7 August 2026 to remediate under the KEV timeline.&lt;/p&gt;

&lt;p&gt;The through-line for a defender is that the window for treating this as theoretical closed on 4 August. If your receiver is reachable, you are now inside an actively exploited exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;For teams running Java platforms in India, two points sharpen the priority. Under the Digital Personal Data Protection Act 2023, an unauthorised access to session data replicated across a cluster is a personal data breach if those sessions carry personal data, which most authenticated web sessions do, and that triggers notification obligations you can only assess if you have retained the receiver logs. Keep the &lt;code&gt;Failed to decrypt message&lt;/code&gt; events and inbound connection logs on port 4000; they are the evidence of whether the sink was hit.&lt;/p&gt;

&lt;p&gt;The cost context is not abstract either. IBM's 2026 Cost of a Data Breach Report, released 3 August 2026, puts the average Indian breach at ₹25.5 crore, up 15.9% year on year, against a global average of $4.99 million, and it names offensive security testing as India's single largest cost-reducing factor, saving an average of ₹2.47 crore. A deserialization sink on a clustering port is exactly the kind of finding a penetration test surfaces before an attacker does.&lt;/p&gt;

&lt;p&gt;For the wider pattern of treating emergency patches as the start rather than the end of the work, our &lt;a href="https://ecorpit.com/nodejs-security-release-july-2026-patch-response-playbook/" rel="noopener noreferrer"&gt;Node.js July 2026 patch response playbook&lt;/a&gt; and our approach to &lt;a href="https://ecorpit.com/oracle-july-2026-critical-patch-update-triage-guide/" rel="noopener noreferrer"&gt;triaging a large Oracle Critical Patch Update by risk&lt;/a&gt; apply the same discipline to other stacks. This piece sits in our web and API engineering cluster under the &lt;a href="https://ecorpit.com/interop-2026-web-platform-developer-guide/" rel="noopener noreferrer"&gt;Interop 2026 web platform developer guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to change so the next one is cheaper
&lt;/h2&gt;

&lt;p&gt;Three habits that would have blunted this specific bug.&lt;/p&gt;

&lt;p&gt;Treat any security patch to a component you rely on for a trust boundary as a change that needs its own verification, not a routine bump. The fix for CVE-2026-29146 was itself a security fix, and it opened CVE-2026-34486. A quick post-upgrade check that the encryption gate still drops undecryptable traffic would have caught the regression.&lt;/p&gt;

&lt;p&gt;Assume every internal listening port is reachable by an attacker who has a foothold somewhere in your network, and segment accordingly. The Kubernetes namespace trap is the clearest example, but it applies to any flat network.&lt;/p&gt;

&lt;p&gt;Put a JVM deserialization filter in place before you need it. It is the one control here that would have stopped exploitation even on a fully vulnerable, fully exposed node, because it operates at the sink rather than the perimeter. The perimeter is where you hope the attacker is not; the sink is where the code actually runs.&lt;/p&gt;

&lt;p&gt;The real cost of this class of bug is rarely the upgrade. It is the deserialization sink you left unfiltered because the encryption in front of it was supposed to be enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Am I affected if I run Tomcat but do not use clustering?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. CVE-2026-34486 only affects deployments that enable Tribes clustering with &lt;code&gt;EncryptInterceptor&lt;/code&gt; configured on an affected build. If &lt;code&gt;grep -rn "EncryptInterceptor" $CATALINA_HOME/conf/&lt;/code&gt; returns nothing, the vulnerable receive path is not in your interceptor chain and this CVE does not apply, even on version 11.0.20, 10.1.53 or 9.0.116.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which exact versions do I need to move off?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The affected builds are 11.0.20, 10.1.53 and 9.0.116. Upgrade to 11.0.21, 10.1.54 or 9.0.117 respectively, all released between 2 and 4 April 2026. Builds earlier than the affected ones, such as 11.0.18, never had the regression, and Tomcat 8.5.x is not affected because it has no &lt;code&gt;EncryptInterceptor&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does patching fully fix the problem?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Patching restores fail-closed behaviour and closes this specific regression. It does not filter the underlying &lt;code&gt;ObjectInputStream.readObject()&lt;/code&gt; sink, which still runs on decrypted messages. Add a JVM-wide &lt;code&gt;jdk.serialFilter&lt;/code&gt;, remove unused gadget libraries, and restrict the receiver port, so a future bug in the same path does not reach code execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does the encryption not protect me?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The encryption is the component that failed. The regression made &lt;code&gt;EncryptInterceptor&lt;/code&gt; forward messages that fail decryption instead of dropping them, so undecryptable attacker bytes reach the deserialization routine anyway. The encryption layer became a gate that could be bypassed rather than a hard stop, which is why configured encryption offers no protection on the affected versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does exploitation look like in my logs?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A single SEVERE entry reading "Failed to decrypt message" from &lt;code&gt;EncryptInterceptor.messageReceived&lt;/code&gt;, typically with an &lt;code&gt;AEADBadTagException&lt;/code&gt; or &lt;code&gt;BadPaddingException&lt;/code&gt;. No deserialization error follows, because the gadget runs silently. Correlate those entries with unexpected inbound TCP connections to the receiver port, 4000 by default, to spot attempts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is CVE-2026-34486 being exploited in the wild?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, as of 4 August 2026. CISA added it to the Known Exploited Vulnerabilities catalog that day, and The Hacker News reported exploitation attributed to an autonomous AI-driven campaign that Palo Alto Networks Unit 42 links to an actor operating as knaithe. When SOCRadar assessed it in April 2026 there was no confirmed exploitation, so the status changed over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the fastest interim control if I cannot patch today?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Restrict network access to the receiver port. Bind the &lt;code&gt;Receiver&lt;/code&gt; to a private cluster-only interface and firewall TCP 4000 to peer nodes only. In Kubernetes, apply a default-deny NetworkPolicy that permits port 4000 solely between the cluster's own pods, which removes the same-namespace reachability that otherwise exposes every node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does a modern JDK protect against the gadget chain?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not by itself. JDK 8u72 broke the older CommonsCollections1 and CC3 chains, but the CommonsCollections6 chain uses &lt;code&gt;HashSet&lt;/code&gt; as its entry point and works on JDK 17 and 21. A current runtime does not remove the deserialization risk; a configured &lt;code&gt;jdk.serialFilter&lt;/code&gt; and a clean classpath do.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT is a senior-led engineering organisation in Gurugram, ISO 27001:2022 certified and assessed at CMMI Level 5, and we do Java platform hardening and application portfolio analysis for teams running Tomcat, Spring and legacy clustered deployments. For this issue that means auditing your interceptor configuration and receiver exposure, applying the patch across environments, and putting a tested deserialization filter and network segmentation in place so the sink is closed for good. We also run &lt;a href="https://ecorpit.com/ecorpit-api-integration-modernization-service-india-2026/" rel="noopener noreferrer"&gt;API integration and modernization work&lt;/a&gt; on the same stacks, and design applications aligned with DPDP Act 2023 requirements. If you run Tomcat clustering and are not sure whether you are exposed, talk to us at &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;/contact-us/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.striga.ai/research/tomcat-tribes-unauth-rce" rel="noopener noreferrer"&gt;Fail Open, Game Over: Turning a One-Line Tomcat Fix into Unauthenticated RCE&lt;/a&gt; - Striga&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-34486" rel="noopener noreferrer"&gt;CVE-2026-34486 record&lt;/a&gt; - CVE Program&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-29146" rel="noopener noreferrer"&gt;CVE-2026-29146 record&lt;/a&gt; - CVE Program&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://socradar.io/cve-2026-34486-apache-tomcat-tribes-rce/" rel="noopener noreferrer"&gt;CVE-2026-34486: Apache Tomcat Tribes Regression Creates Unauthenticated RCE Path&lt;/a&gt; - SOCRadar&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tomcat.apache.org/security-11.html" rel="noopener noreferrer"&gt;Apache Tomcat 11 Security Advisories&lt;/a&gt; - Apache Software Foundation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cisa.gov/news-events/alerts/2026/08/04/cisa-adds-three-known-exploited-vulnerabilities-catalog" rel="noopener noreferrer"&gt;CISA Adds Three Known Exploited Vulnerabilities to Catalog, 4 August 2026&lt;/a&gt; - CISA&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog" rel="noopener noreferrer"&gt;Known Exploited Vulnerabilities Catalog&lt;/a&gt; - CISA&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://thehackernews.com/2026/08/cisa-flags-langflow-rce-tomcat-and-n.html" rel="noopener noreferrer"&gt;CISA Flags Langflow RCE, Tomcat, and N-central Flaws as Actively Exploited&lt;/a&gt; - The Hacker News, 5 August 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/apache/tomcat/commit/6d955cceca841f2eabf2d6c46b59a8c7e1cd6eaa" rel="noopener noreferrer"&gt;The regression commit on the 11.0.x branch&lt;/a&gt; - Apache Tomcat, GitHub&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cwe.mitre.org/data/definitions/502.html" rel="noopener noreferrer"&gt;CWE-502: Deserialization of Untrusted Data&lt;/a&gt; - MITRE&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cwe.mitre.org/data/definitions/636.html" rel="noopener noreferrer"&gt;CWE-636: Not Failing Securely (Fail Open)&lt;/a&gt; - MITRE&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://in.newsroom.ibm.com/India-Records-its-Highest-Average-Cost-of-a-Data-Breach-2026" rel="noopener noreferrer"&gt;India Records Its Highest Average Cost of a Data Breach at INR 255 Million in 2026&lt;/a&gt; - IBM, 3 August 2026&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last updated: 5 August 2026.&lt;/p&gt;

</description>
      <category>cve202634486</category>
      <category>apachetomcat</category>
      <category>javadeserialization</category>
      <category>tomcattribes</category>
    </item>
    <item>
      <title>Air-gapped Gemini vs in-country Gemini Enterprise: what DPDP and RBI actually require in 2026</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 10:11:38 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/air-gapped-gemini-vs-in-country-gemini-enterprise-what-dpdp-and-rbi-actually-require-in-2026-3pig</link>
      <guid>https://dev.to/mr_manushukla/air-gapped-gemini-vs-in-country-gemini-enterprise-what-dpdp-and-rbi-actually-require-in-2026-3pig</guid>
      <description>&lt;h1&gt;
  
  
  Air-gapped Gemini vs in-country Gemini Enterprise: what DPDP and RBI actually require in 2026
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; At Google I/O Connect India on 14 July 2026, Google made Gemini available inside Indian data centres in two quite different shapes. The first runs Gemini on Google Distributed Cloud with, in Google's words, "prompts, model weights or outputs" never leaving the customer perimeter, and with "all supporting services" running "fully disconnected from the public internet" behind what Google calls a "physical airlock". The second makes Gemini 3.5 Flash available through the Gemini Enterprise Agent Platform and the Gemini Enterprise app with in-country machine-learning processing commitments — a regional cloud service, generally available for India with an allowlist since 30 June 2026, not a disconnected installation. These are not two tiers of the same product. They differ on cost, on model freshness, on operational burden, and on what they actually prove to a regulator. The Reserve Bank of India's directive on storage of payment system data (RBI/2017-18/153, DPSS.CO.OD No.2785/06.08.005/2017-2018) requires that "the entire data relating to payment systems operated by them are stored in a system only in India" — and the RBI's own clarification adds that "There is no bar on processing of payment transactions outside India if so desired by the PSOs. However, the data shall be stored only in India after the processing." India's Digital Personal Data Protection Rules were notified on 14 November 2025 with obligations on a phased schedule. Neither instrument requires an air gap for most workloads. Air-gapped Gemini solves a real problem for a narrow set of organisations. For everyone else it is a large bill for a control nobody asked for.&lt;/p&gt;

&lt;p&gt;The published prices show the gap in what you can even evaluate. Gemini 3.5 Flash lists at $1.50 per 1M input tokens and $9.00 per 1M output tokens on the standard tier, halving to $0.75 and $4.50 on batch. Google has published no India pricing for the air-gapped Distributed Cloud deployment at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Google actually announced, in its own words
&lt;/h2&gt;

&lt;p&gt;The distinction is easy to blur because both announcements arrived on the same day. Google's India blog post separates them clearly.&lt;/p&gt;

&lt;p&gt;On the air-gapped option: "Indian enterprises including regulated industries and the public sector can now run Gemini on Google Distributed Cloud from within Indian data centres. This allows enterprises and public sector organisations to deploy advanced generative AI without prompts, model weights or outputs leaving their perimeter… All supporting services will run fully disconnected from the public internet, providing a 'physical airlock' that will mitigate the risk of external data breaches."&lt;/p&gt;

&lt;p&gt;On the managed option: "We also expanded our commitment to India's digital sovereignty by making Gemini 3.5 Flash available to Indian enterprises and startups via the Gemini Enterprise Agent Platform and the Gemini Enterprise app… this model will be available with strict in-country machine learning processing commitments."&lt;/p&gt;

&lt;p&gt;TechRepublic's 21 July 2026 write-up is worth reading alongside it for two clarifications Google's post does not make. First, air-gapped Gemini is not new — Google made it generally available in August 2025, and "the July 2026 announcement extends the deployment option to Indian data centers." Second, and more usefully: the Gemini Enterprise path "is a regional cloud service, not the disconnected Google Distributed Cloud installation." Same brand, different architecture, different assurance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the regulations actually say
&lt;/h2&gt;

&lt;p&gt;This is where most vendor comparisons stop being useful, because they conflate three separate things: data residency, processing location, and network isolation. Indian law treats them differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RBI, payment system data.&lt;/strong&gt; The 2018 directive is specific and narrow. It applies to payment system operators, banks, non-bank prepaid instrument issuers and card networks, and it covers "Customer data (Name, Mobile Number, email, Aadhaar Number, PAN number, etc. as applicable); Payment sensitive data (customer and beneficiary account details); Payment Credentials (OTP, PIN, Passwords, etc.); and, Transaction data". The requirement is storage: that data must live in a system in India. The RBI's clarification explicitly permits offshore processing so long as the data is stored only in India afterwards. There is no isolation requirement in the text, and there is no requirement that the machine doing the inference be disconnected from the internet.&lt;/p&gt;

&lt;p&gt;What the RBI does emphasise, in the same directive, is supervisory reach: "it is important to have unfettered supervisory access to data stored with these system providers as also with their service providers / intermediaries / third party vendors and other entities in the payment ecosystem." Read that carefully. The regulator's stated concern is access and auditability, not air gaps. An architecture that gives your supervisor clean audit access matters more than one that unplugs the network cable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DPDP.&lt;/strong&gt; India notified the Digital Personal Data Protection Rules on 14 November 2025, with major obligations taking effect on a phased schedule. DPDP obligations attach to consent, purpose limitation, retention, deletion, breach notification and the rights of data principals. Local hosting does not settle any of those. As TechRepublic puts it, "Local hosting does not settle requirements for consent, access, retention, deletion, or incident response." A team that buys an air gap and does not build a deletion pipeline has spent money on the wrong problem.&lt;/p&gt;

&lt;p&gt;The practical conclusion for most organisations: your obligation is to know where the data rests, to control who can reach it, to prove both, and to be able to delete it. Isolation is one way to achieve some of that. It is rarely the cheapest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three-way comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Air-gapped Gemini on Google Distributed Cloud&lt;/th&gt;
&lt;th&gt;In-country Gemini Enterprise (regional cloud)&lt;/th&gt;
&lt;th&gt;Global multi-region Gemini API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where prompts, weights and outputs sit&lt;/td&gt;
&lt;td&gt;Inside the customer perimeter; Google states none of them leave it&lt;/td&gt;
&lt;td&gt;In Google Cloud India regions, with in-country machine-learning processing commitments&lt;/td&gt;
&lt;td&gt;Wherever the API routes, subject to your configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network posture&lt;/td&gt;
&lt;td&gt;Supporting services run fully disconnected from the public internet, with a controlled "physical airlock" transfer process&lt;/td&gt;
&lt;td&gt;Connected regional cloud service; perimeter enforced with VPC Service Controls and IAM&lt;/td&gt;
&lt;td&gt;Connected; residency controls only where offered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model freshness&lt;/td&gt;
&lt;td&gt;Updates arrive through the controlled transfer process, on your schedule&lt;/td&gt;
&lt;td&gt;Google-managed; Gemini 3.5 Flash available for India on an allowlist since 30 June 2026&lt;/td&gt;
&lt;td&gt;Newest models first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Published pricing&lt;/td&gt;
&lt;td&gt;None published for India as of August 2026&lt;/td&gt;
&lt;td&gt;Gemini 3.5 Flash at $1.50 / $9.00 per 1M tokens standard, $0.75 / $4.50 batch&lt;/td&gt;
&lt;td&gt;Same public list pricing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational burden&lt;/td&gt;
&lt;td&gt;Highest: hardware, update approvals, key custody, physical process&lt;/td&gt;
&lt;td&gt;Moderate: cloud configuration, org policy constraints, key management&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit position&lt;/td&gt;
&lt;td&gt;Strongest isolation story; independent assessments for India not yet detailed publicly&lt;/td&gt;
&lt;td&gt;Google contractually grants audit, access and information rights to regulated entities and their supervisors; PCI DSS third-party audited at least annually; GCP empanelled by MeitY&lt;/td&gt;
&lt;td&gt;Weakest for regulated payment data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fits&lt;/td&gt;
&lt;td&gt;Classified government workloads, defence-adjacent, organisations with an explicit no-internet mandate&lt;/td&gt;
&lt;td&gt;Most BFSI, healthcare and public-sector generative AI work&lt;/td&gt;
&lt;td&gt;Non-regulated workloads and internal tooling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two rows deserve expansion.&lt;/p&gt;

&lt;p&gt;The pricing row is not a gap in this article — it is a gap in the market. TechRepublic's conclusion is blunt and correct: "Until Google details India-specific pricing, hardware, independent assessments, and production deployments, buyers cannot fully compare the offering's cost, controls, or operational maturity." If you are being asked to approve an air-gapped deployment, that sentence is your negotiating position. Ask for the number, the hardware bill of materials, and the name of an independent assessor before the architecture review, not after.&lt;/p&gt;

&lt;p&gt;The audit row is where the managed path is stronger than teams expect. Google's own RBI data-localization whitepaper states that customers can configure services to store payment data in Mumbai (&lt;code&gt;asia-south1&lt;/code&gt;) or Delhi (&lt;code&gt;asia-south2&lt;/code&gt;), that "Google grants audit, access and information rights to regulated entities, their supervisory authorities and both their appointees", and that Google Cloud "aligns to RBI Guidelines on Managing Risks and Code of Conduct in Outsourcing of Financial Services by Banks". That is a documented, contractual answer to the RBI's supervisory-access concern. The air-gapped option's India-specific equivalent has not been published.&lt;/p&gt;

&lt;h2&gt;
  
  
  The controls that do the work on the managed path
&lt;/h2&gt;

&lt;p&gt;If you take the in-country route, the residency claim is only as good as the configuration. Four controls from Google's own documentation carry most of the weight.&lt;/p&gt;

&lt;p&gt;Organization Policy resource-location constraints limit where a new resource may be created, applied at organization, folder or project level. This is what stops an engineer in a hurry from spinning up a bucket in &lt;code&gt;us-central1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;VPC Service Controls define a service perimeter — "the virtual boundaries from which a service can be accessed, preventing data from being moved outside those boundaries." Google positions this as context-based perimeter security that works independently of IAM and mitigates exfiltration through misconfigured access or compromised accounts. For a generative AI workload, this is the control that stops prompts and outputs leaving the perimeter, and it is the closest managed-cloud analogue to what the air gap achieves physically.&lt;/p&gt;

&lt;p&gt;Cloud KMS customer-managed keys. Data at rest is encrypted with Google-managed keys by default; regulated entities handling financial information can hold their own keys instead. Whoever holds the key is a question your regulator will ask, and "Google" is a weaker answer than "we do".&lt;/p&gt;

&lt;p&gt;IAM with fine-grained policies, which Google notes helps "prevent your employees from accidentally storing customer data in the wrong Google Cloud region."&lt;/p&gt;

&lt;p&gt;None of these are new, and that is the point. A well-configured regional deployment is a known quantity with contractual audit rights, published pricing and years of third-party assessment behind it. An air gap is a stronger physical story with, for India specifically, less published evidence attached to it so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to verify before signing either contract
&lt;/h2&gt;

&lt;p&gt;TechRepublic's checklist for the air-gapped option is the right one and it applies, with adjustments, to both. Buyers "must still verify privileged access, encryption-key control, software-update procedures, and proof that data remains inside the approved environment."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;th&gt;What good looks like&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who holds the encryption keys, and can the vendor decrypt without you?&lt;/td&gt;
&lt;td&gt;Determines whether residency is a technical control or a promise&lt;/td&gt;
&lt;td&gt;Customer-managed keys with documented custody and rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who has privileged access during a support incident?&lt;/td&gt;
&lt;td&gt;Support access is the usual hole in an isolation story&lt;/td&gt;
&lt;td&gt;Named roles, break-glass logged and reviewable, contractual limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How do software and model updates enter the environment?&lt;/td&gt;
&lt;td&gt;The transfer process is the only path in; it is also the only attack path in&lt;/td&gt;
&lt;td&gt;Authenticated packages, staged testing, approval controls, rollback, change records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What evidence proves data stayed inside?&lt;/td&gt;
&lt;td&gt;This is what your auditor will ask for&lt;/td&gt;
&lt;td&gt;Network isolation evidence, in-country processing attestations, administrator access logs, retention and deletion records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What are the audit and supervisory access rights?&lt;/td&gt;
&lt;td&gt;The RBI's stated concern is unfettered supervisory access&lt;/td&gt;
&lt;td&gt;Contractual rights extending to the regulator and its appointees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What is the India price, and what hardware does it assume?&lt;/td&gt;
&lt;td&gt;Not published for the air-gapped option as of August 2026&lt;/td&gt;
&lt;td&gt;A written quote with the hardware bill of materials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Which model versions, and on what update cadence?&lt;/td&gt;
&lt;td&gt;Isolation costs you model freshness&lt;/td&gt;
&lt;td&gt;A named model, a stated update path, and who decides when to take one&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The update question is the one teams under-weight. An air-gapped environment is, by construction, a place where new models arrive late and only when someone approves the transfer. If your use case depends on being current — coding assistance, agentic workflows, anything where capability moves quarterly — you are trading capability for isolation. That trade is correct for some workloads and wrong for most.&lt;/p&gt;

&lt;h2&gt;
  
  
  A decision path
&lt;/h2&gt;

&lt;p&gt;Work through these in order. Stop at the first one that gives you a clear answer.&lt;/p&gt;

&lt;p&gt;Do you have an explicit written mandate, from a regulator, a ministry or a customer contract, that the processing environment must be disconnected from the public internet? If yes, air-gapped Distributed Cloud is your candidate and the rest of this article is a checklist for buying it well. If no, keep going — because in our reading, RBI's payment-data directive and the DPDP Rules do not create that mandate.&lt;/p&gt;

&lt;p&gt;Is the data in scope payment system data as the RBI defines it? If yes, your requirement is storage in India, and the RBI's clarification is explicit that processing may occur abroad provided storage afterwards is in India only. A configured India-region deployment with resource-location constraints and VPC Service Controls addresses that, with contractual audit rights on top.&lt;/p&gt;

&lt;p&gt;Is the sensitivity in the data or in the inference? A model that summarises customer complaints is a different risk from a model that sees full payment credentials. If you can keep the regulated fields out of the prompt entirely — tokenise, redact, or retrieve by reference — you may find the residency question shrinks to something the managed path handles comfortably.&lt;/p&gt;

&lt;p&gt;Can you carry the operational burden? An air-gapped platform is hardware, physical process, key custody, an update approval workflow and the staff to run all of it. Organisations that already operate isolated environments will absorb this. Organisations that have run entirely on managed cloud for a decade usually underestimate it by a factor of two.&lt;/p&gt;

&lt;p&gt;The honest engineering judgement: most Indian BFSI and healthcare generative AI workloads are correctly served by the in-country managed path with the perimeter controls configured properly and the audit rights exercised. Air-gapped Gemini is the right answer for a genuinely narrow set of classified and critical-infrastructure workloads, and buying it for the others substitutes a purchase for a design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The security features announced alongside it
&lt;/h2&gt;

&lt;p&gt;Two other items from the same event affect this decision and are worth tracking rather than assuming.&lt;/p&gt;

&lt;p&gt;CAPSEM is an open-source runtime designed to isolate AI agents inside virtual machines and keep raw credentials out of their reach. That addresses a real failure mode — agents granted human-level access without runtime monitoring — and it is relevant whether or not you air-gap.&lt;/p&gt;

&lt;p&gt;Sec-Gemini v3 is being given to selected government and enterprise testers, Flipkart among them, for incident investigation, digital forensics and malware analysis. TechRepublic notes that these programmes "were announced separately and are not identified as standard components of every air-gapped deployment", which is the kind of distinction that gets lost between a launch blog and a procurement document.&lt;/p&gt;

&lt;p&gt;Device Bound Session Credentials, aimed at making stolen session credentials harder to reuse on another device, remains a W3C First Public Working Draft rather than a finished standard. Plan accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;Beyond the regulatory reading above, three practical points for teams in Gurugram, Mumbai, Bengaluru and Hyderabad.&lt;/p&gt;

&lt;p&gt;Region choice is a decision, not a default. Google Cloud's India regions for payment data residency are Mumbai (&lt;code&gt;asia-south1&lt;/code&gt;) and Delhi (&lt;code&gt;asia-south2&lt;/code&gt;). Latency to end users, disaster-recovery pairing and the location of your existing data estate should all feed that choice, and the resource-location constraint should be set at the organisation level so it is not re-litigated per project.&lt;/p&gt;

&lt;p&gt;Foreign banks and their Indian operations face the tightest version of the storage requirement, and the payment-data directive's scope covers service providers and third-party vendors in the payment ecosystem, not only the regulated entity itself. If your generative AI vendor touches payment data, the localisation question follows the data into their stack. Ask them the same seven questions in the table above.&lt;/p&gt;

&lt;p&gt;For public-sector and government-adjacent work, MeitY empanelment matters procedurally, and Google Cloud states that GCP is empanelled by MeitY. That is a procurement fact worth confirming for the specific services in your architecture rather than for the platform in general.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does RBI require an air-gapped environment for AI workloads?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not in the text of the payment-data directive. RBI/2017-18/153 requires that data relating to payment systems be "stored in a system only in India", and the RBI's clarification states there is "no bar on processing of payment transactions outside India" provided the data is stored only in India afterwards. The directive emphasises supervisory access, not network isolation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the difference between the two Gemini options Google announced for India?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Air-gapped Gemini runs on Google Distributed Cloud inside Indian data centres with supporting services disconnected from the public internet and a controlled transfer process. The Gemini Enterprise path is a regional cloud service offering Gemini 3.5 Flash with in-country machine-learning processing commitments. Different architectures, different assurance, different operational burden.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is air-gapped Gemini new?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not globally. Google made air-gapped Gemini generally available in August 2025, and the 14 July 2026 India announcement extends that deployment option to Indian data centres. What is new for Indian buyers is the ability to run it locally rather than the capability itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does the in-country Gemini Enterprise option cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gemini 3.5 Flash lists at $1.50 per 1M input tokens and $9.00 per 1M output tokens on the standard tier, dropping to $0.75 and $4.50 on the batch tier. Google has not published India-specific pricing for the air-gapped Distributed Cloud deployment, which limits any direct cost comparison between the two options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does hosting in India satisfy DPDP?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. The Digital Personal Data Protection Rules were notified on 14 November 2025 with obligations phased in, and they govern consent, purpose limitation, retention, deletion, breach notification and data-principal rights. Local hosting addresses none of those directly. Residency and DPDP compliance are separate workstreams that teams frequently conflate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which controls make a managed India-region deployment defensible?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Four: Organization Policy resource-location constraints to pin where resources may be created, VPC Service Controls to define a perimeter that prevents data moving outside it, Cloud KMS customer-managed keys so your organisation holds the keys, and fine-grained IAM. Google also contractually grants audit and access rights to regulated entities and their supervisors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should we ask before approving an air-gapped deployment?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seven things: who holds encryption keys, who has privileged access during support incidents, how updates enter the environment, what evidence proves data stayed inside, what audit rights extend to your regulator, what the India price and hardware assumptions are, and which model versions you get on what cadence. The last one is the trade you are actually making.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the cost of choosing isolation?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Model freshness and operational load. In a disconnected environment, new models arrive only through an approved transfer, so you are always behind the managed path. You also take on hardware, key custody, update approval workflows and the staff to run them. For workloads where capability moves quarterly, that is an expensive trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;We help Indian BFSI, healthcare and public-sector teams answer this question with evidence rather than vendor framing: map the data actually entering the prompt, read the obligation against the specific directive that applies, and design the smallest architecture that satisfies it. eCorpIT is CMMI Level 5 and ISO 27001:2022 certified, we are a Google partner, and our senior engineering teams design deployments aligned with DPDP requirements. If an air-gapped proposal is on your desk and nobody has checked whether the regulation asks for it, &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;talk to us&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Related reading: our &lt;a href="https://ecorpit.com/ecorpit-data-residency-dpdp-cloud-architecture-service-india-2026/" rel="noopener noreferrer"&gt;data residency and DPDP cloud architecture service&lt;/a&gt; covers the design work behind this decision, the &lt;a href="https://ecorpit.com/india-sovereign-ai-indiaai-mission-dpdp-2026/" rel="noopener noreferrer"&gt;India sovereign AI and IndiaAI Mission analysis&lt;/a&gt; sets it in policy context, the &lt;a href="https://ecorpit.com/dpdp-act-engineering-playbook-indian-startups-2026/" rel="noopener noreferrer"&gt;DPDP engineering playbook&lt;/a&gt; is the pillar for this cluster, and the &lt;a href="https://ecorpit.com/gemini-enterprise-governance-billing-eval-token-cost-control-2026/" rel="noopener noreferrer"&gt;Gemini Enterprise governance and cost control guide&lt;/a&gt; covers running the managed path once you have chosen it.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://blog.google/intl/en-in/company-news/deepening-our-commitment-to-indias-ai-ambition/" rel="noopener noreferrer"&gt;Deepening our commitment to India's AI ambition (I/O Connect India 2026 announcements) — Google India Blog, 14 July 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techrepublic.com/article/news-air-gapped-gemini-apac-india/" rel="noopener noreferrer"&gt;Google Brings Air-Gapped Gemini to India for Regulated Enterprises — TechRepublic, 21 July 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/security/compliance/rbi_guidelines_data_localization_whitepaper" rel="noopener noreferrer"&gt;How GCP addresses Data Localization for payment data per RBI Guidelines — Google Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.meity.gov.in/documents/act-and-policies/digital-personal-data-protection-rules-2025-gDOxUjMtQWa" rel="noopener noreferrer"&gt;Digital Personal Data Protection Rules 2025 — Ministry of Electronics and Information Technology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/pricing" rel="noopener noreferrer"&gt;Gemini Developer API pricing — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/gemini/enterprise/docs/release-notes" rel="noopener noreferrer"&gt;Gemini Enterprise release notes — Google Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/topics/hybrid-cloud/gemini-is-now-available-anywhere" rel="noopener noreferrer"&gt;Gemini is now available anywhere: air-gapped Google Distributed Cloud — Google Cloud Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.google/innovation-and-ai/infrastructure-and-cloud/google-cloud/gemini-enterprise-agent-platform/" rel="noopener noreferrer"&gt;Introducing the Gemini Enterprise Agent Platform — Google Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/products/ai-machine-learning/introducing-gemini-enterprise" rel="noopener noreferrer"&gt;Introducing Gemini Enterprise — Google Cloud Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.google/intl/en-in/company-news/building-the-safety-foundations-for-indias-agentic-future/" rel="noopener noreferrer"&gt;Building the safety foundations for India's agentic future (CAPSEM, Sec-Gemini v3) — Google India Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/dbsc/" rel="noopener noreferrer"&gt;Device Bound Session Credentials — W3C First Public Working Draft&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mediabrief.com/google-i-o-connect-india-2026-accelerates-ai-adoption-across-india/" rel="noopener noreferrer"&gt;Google I/O Connect India 2026 accelerates AI adoption across India — MediaBrief&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Last updated: 5 August 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>googledistributedclo</category>
      <category>geminienterprise</category>
      <category>dataresidency</category>
      <category>dpdp</category>
    </item>
    <item>
      <title>Imagen 4 shuts down 17 August 2026: the generate_content() migration, with cost math</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 10:07:25 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/imagen-4-shuts-down-17-august-2026-the-generatecontent-migration-with-cost-math-4dfd</link>
      <guid>https://dev.to/mr_manushukla/imagen-4-shuts-down-17-august-2026-the-generatecontent-migration-with-cost-math-4dfd</guid>
      <description>&lt;h1&gt;
  
  
  Imagen 4 shuts down 17 August 2026: the generate_content() migration, with cost math
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; Google shuts down all three Imagen 4 models, &lt;code&gt;imagen-4.0-generate-001&lt;/code&gt;, &lt;code&gt;imagen-4.0-ultra-generate-001&lt;/code&gt; and &lt;code&gt;imagen-4.0-fast-generate-001&lt;/code&gt;, on 17 August 2026, twelve days from now. The Gemini API deprecations table names &lt;code&gt;gemini-3.1-flash-image&lt;/code&gt; as the recommended replacement. Google's own Imagen documentation page, last updated 16 July 2026, names a different one: "Use &lt;code&gt;gemini-2.5-flash-image&lt;/code&gt; instead of Imagen model names." Follow that second instruction and you land on a model with its own shutdown date of 2 October 2026, a second migration 46 days after the first. The code change is three breaking edits: &lt;code&gt;client.models.generate_images()&lt;/code&gt; becomes &lt;code&gt;client.models.generate_content()&lt;/code&gt;, images arrive as content parts rather than in a &lt;code&gt;generated_images&lt;/code&gt; array, and &lt;code&gt;number_of_images&lt;/code&gt; (default 4, range 1–4) does not exist on Gemini image models, so one call now produces one image. On cost, &lt;code&gt;gemini-3.1-flash-image&lt;/code&gt; bills image output at $60.00 per 1M tokens, which Google works out to $0.045 per 0.5K image, $0.067 per 1K image, $0.101 per 2K and $0.151 per 4K. The batch tier halves that to $0.034 per 1K image, and &lt;code&gt;gemini-3.1-flash-lite-image&lt;/code&gt; lists $0.0336 per 1K image on the standard tier. Imagen 4's own prices are no longer published on the Gemini API pricing page at all.&lt;/p&gt;

&lt;p&gt;Two other Gemini API shutdowns land in the same window and are easy to miss while you are looking at images: &lt;code&gt;embedding-2-preview&lt;/code&gt; on 10 August 2026, and &lt;code&gt;gemini-robotics-er-1.6-preview&lt;/code&gt; on 31 August 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which replacement model is actually correct
&lt;/h2&gt;

&lt;p&gt;This is the part to get right before you write any code, because Google's documentation gives two different answers.&lt;/p&gt;

&lt;p&gt;The deprecations page, which is the page Google explicitly designates as the tracker, "the announced earliest shutdown dates are tracked on this page", lists all three Imagen 4 models with a shutdown date of 17 August 2026 and a recommended replacement of &lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;. That model has no shutdown date announced.&lt;/p&gt;

&lt;p&gt;The Imagen guide page says something else. Its "Migration to Nano Banana" section instructs: "&lt;strong&gt;Model name&lt;/strong&gt;: Use &lt;code&gt;gemini-2.5-flash-image&lt;/code&gt; instead of Imagen model names." But the same deprecations table lists &lt;code&gt;gemini-2.5-flash-image&lt;/code&gt; with a shutdown date of 2 October 2026 and a recommended replacement of &lt;code&gt;gemini-3.1-flash-image-preview&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Status per the deprecations table&lt;/th&gt;
&lt;th&gt;Shutdown date&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;imagen-4.0-generate-001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deprecated&lt;/td&gt;
&lt;td&gt;17 August 2026&lt;/td&gt;
&lt;td&gt;Must move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;imagen-4.0-ultra-generate-001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deprecated&lt;/td&gt;
&lt;td&gt;17 August 2026&lt;/td&gt;
&lt;td&gt;Must move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;imagen-4.0-fast-generate-001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deprecated&lt;/td&gt;
&lt;td&gt;17 August 2026&lt;/td&gt;
&lt;td&gt;Must move&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gemini-2.5-flash-image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deprecated&lt;/td&gt;
&lt;td&gt;2 October 2026&lt;/td&gt;
&lt;td&gt;Named by the Imagen guide, do not migrate here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Released 28 May 2026&lt;/td&gt;
&lt;td&gt;No shutdown date announced&lt;/td&gt;
&lt;td&gt;The correct target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gemini-3.1-flash-lite-image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Listed on the pricing page as the efficiency model&lt;/td&gt;
&lt;td&gt;No shutdown date announced&lt;/td&gt;
&lt;td&gt;The correct target for high-volume, cost-sensitive work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Migrate to &lt;code&gt;gemini-3.1-flash-image&lt;/code&gt; or &lt;code&gt;gemini-3.1-flash-lite-image&lt;/code&gt;. Treat the Imagen guide's &lt;code&gt;gemini-2.5-flash-image&lt;/code&gt; line as stale documentation, not guidance. A stale doc page is the most expensive kind of bug on a deadline, because it looks authoritative and it costs you the whole migration twice.&lt;/p&gt;

&lt;p&gt;One caveat worth stating plainly. Google's deprecations page carries a note that the listed dates "indicate the &lt;em&gt;earliest possible dates&lt;/em&gt; on which a model might be retired" and that "We will communicate the exact shutdown date to users with advance notice." That softens the date in theory. It is not a reason to plan past 17 August.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three breaking changes
&lt;/h2&gt;

&lt;p&gt;Here is the Imagen 4 call as Google's own documentation writes it, with &lt;code&gt;number_of_images&lt;/code&gt; set to 4:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.genai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_images&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;imagen-4.0-generate-001&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Robot holding a red skateboard&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GenerateImagesConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;number_of_images&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;generated_image&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generated_images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;generated_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things in that snippet stop working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The method changes.&lt;/strong&gt; &lt;code&gt;client.models.generate_images&lt;/code&gt; becomes &lt;code&gt;client.models.generate_content&lt;/code&gt;. This is not an alias; the Imagen path used a &lt;code&gt;:predict&lt;/code&gt; endpoint (&lt;code&gt;https://generativelanguage.googleapis.com/v1beta/models/imagen-4.0-generate-001:predict&lt;/code&gt;) with an &lt;code&gt;instances&lt;/code&gt;/&lt;code&gt;parameters&lt;/code&gt; request body, and the Gemini path uses standard content generation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The response shape changes.&lt;/strong&gt; Google states it as "Nano Banana returns content parts, which may include image data, instead of a specific image response object." In practice that means walking &lt;code&gt;response.candidates[0].content.parts&lt;/code&gt; and checking each part for &lt;code&gt;inline_data&lt;/code&gt;. Code that reads &lt;code&gt;response.generated_images&lt;/code&gt; throws an attribute error rather than returning an empty list, so this fails loudly, which is the one piece of good news here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;number_of_images&lt;/code&gt; is gone.&lt;/strong&gt; On Imagen 4 the parameter accepted 1 to 4 and defaulted to 4. On the Gemini image models there is no equivalent, and a call returns one image. Every batch of N becomes N calls.&lt;/p&gt;

&lt;p&gt;The replacement shape:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PIL.Image&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.1-flash-image&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Robot holding a red skateboard&lt;/span&gt;&lt;span class="sh"&gt;"&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;part&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;candidates&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="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inline_data&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PIL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inline_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generated_image.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;part.text&lt;/code&gt; branch. Gemini image models can interleave text with images, so a parts loop that assumes every part is an image will crash on the first commentary token. Handle both.&lt;/p&gt;

&lt;h2&gt;
  
  
  A drop-in replacement for number_of_images
&lt;/h2&gt;

&lt;p&gt;If your pipeline asked for four variants per prompt, you now need a fan-out. This helper keeps the old call signature so the rest of your code does not change, runs the calls concurrently, and returns the images in a list the way &lt;code&gt;generated_images&lt;/code&gt; used to.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;concurrent.futures&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;genai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3.1-flash-image&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_one_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return raw PNG bytes for a single generation, or None if the model
    returned only text (a refusal or a safety block).&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prompt&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;part&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;candidates&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="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inline_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inline_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_images&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number_of_images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fan-out replacement for the removed number_of_images parameter.
    Returns fewer than number_of_images if any call produced no image.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;number_of_images&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keep the fan-out small; each call bills separately&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;number_of_images&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;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;futures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_one_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&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;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number_of_images&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;result&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;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two deliberate choices there. It returns a possibly-shorter list rather than padding, because a safety block or a text-only response is a real outcome your caller needs to see rather than a silent retry loop. And it caps the fan-out, because the thing that used to be one billable request is now N billable requests and an unbounded loop is how a test script turns into an invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost math
&lt;/h2&gt;

&lt;p&gt;The prices below are as listed on the Gemini API pricing page in August 2026.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model and tier&lt;/th&gt;
&lt;th&gt;Image output rate&lt;/th&gt;
&lt;th&gt;Per 1K (1024x1024) image&lt;/th&gt;
&lt;th&gt;Text and thinking output&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;, standard&lt;/td&gt;
&lt;td&gt;$60.00 per 1M tokens&lt;/td&gt;
&lt;td&gt;$0.067 (1,120 tokens)&lt;/td&gt;
&lt;td&gt;$3.00 per 1M&lt;/td&gt;
&lt;td&gt;$0.50 per 1M (text/image)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;, batch&lt;/td&gt;
&lt;td&gt;$30.00 per 1M tokens&lt;/td&gt;
&lt;td&gt;$0.034&lt;/td&gt;
&lt;td&gt;$1.50 per 1M&lt;/td&gt;
&lt;td&gt;$0.25 per 1M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gemini-3.1-flash-lite-image&lt;/code&gt;, standard&lt;/td&gt;
&lt;td&gt;$30.00 per 1M tokens&lt;/td&gt;
&lt;td&gt;$0.0336&lt;/td&gt;
&lt;td&gt;$1.50 per 1M&lt;/td&gt;
&lt;td&gt;$0.25 per 1M (text/image/video)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;, 0.5K (512px)&lt;/td&gt;
&lt;td&gt;$60.00 per 1M tokens&lt;/td&gt;
&lt;td&gt;$0.045 (747 tokens)&lt;/td&gt;
&lt;td&gt;,&lt;/td&gt;
&lt;td&gt;,&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;, 2K (2048x2048)&lt;/td&gt;
&lt;td&gt;$60.00 per 1M tokens&lt;/td&gt;
&lt;td&gt;$0.101 (1,680 tokens)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;, 4K (4096x4096)&lt;/td&gt;
&lt;td&gt;$60.00 per 1M tokens&lt;/td&gt;
&lt;td&gt;$0.151 (2,520 tokens)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three observations that matter more than the headline rate.&lt;/p&gt;

&lt;p&gt;Resolution is the biggest lever you control. Going from 4K to 1K on the same model cuts the per-image cost from $0.151 to $0.067, a 56% reduction, because the image consumes 1,120 output tokens instead of 2,520. Most pipelines generating thumbnails, product tiles or social crops are paying 4K rates for assets that get downsampled anyway. Audit your &lt;code&gt;image_size&lt;/code&gt; before you audit anything else.&lt;/p&gt;

&lt;p&gt;Batch is half price and most image pipelines are batchable. Standard 1K at $0.067 becomes $0.034 on the batch tier. If your generation is a nightly job, a content pipeline or anything that does not need a synchronous response, that is a 49% saving for a scheduling change.&lt;/p&gt;

&lt;p&gt;The fan-out has an input-token cost. Under Imagen 4, one call with &lt;code&gt;number_of_images=4&lt;/code&gt; sent the prompt once. Under the Gemini models, four calls send the prompt four times, each billing input at $0.50 per 1M tokens on the standard tier. For a short prompt that is negligible; for a pipeline that sends a long style guide or reference images with every request, it is four times the input bill for the same four outputs. Where you are generating variants of the same prompt, that repeated input is the line item to check.&lt;/p&gt;

&lt;p&gt;Imagen 4's own per-image prices are no longer on the Gemini API pricing page, which lists Imagen only as a navigation link with no rate table. You cannot look up what you are currently paying from the primary source, so pull the actual figure from your billing console rather than a third-party comparison page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you lose, and what you gain
&lt;/h2&gt;

&lt;p&gt;The migration is not purely a rename, and some Imagen-specific configuration has no direct successor in the same form.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Imagen 4 capability&lt;/th&gt;
&lt;th&gt;Detail as documented&lt;/th&gt;
&lt;th&gt;After migration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numberOfImages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1 to 4, default 4&lt;/td&gt;
&lt;td&gt;No equivalent; fan out in application code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;imageSize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;1K&lt;/code&gt; and &lt;code&gt;2K&lt;/code&gt;, Standard and Ultra models only&lt;/td&gt;
&lt;td&gt;Gemini image models are priced at 0.5K, 1K, 2K and 4K, so 4K becomes available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aspectRatio&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"1:1"&lt;/code&gt;, &lt;code&gt;"3:4"&lt;/code&gt;, &lt;code&gt;"4:3"&lt;/code&gt;, &lt;code&gt;"9:16"&lt;/code&gt;, &lt;code&gt;"16:9"&lt;/code&gt;, default &lt;code&gt;"1:1"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Check the image generation guide for the current parameter before assuming parity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;personGeneration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"dont_allow"&lt;/code&gt;, &lt;code&gt;"allow_adult"&lt;/code&gt; (default), &lt;code&gt;"allow_all"&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Verify the equivalent control; &lt;code&gt;"allow_all"&lt;/code&gt; was already blocked in EU, UK, CH and MENA locations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompt length&lt;/td&gt;
&lt;td&gt;Maximum 480 tokens, English only&lt;/td&gt;
&lt;td&gt;Gemini image models are general multimodal models, not subject to the Imagen text-only limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SynthID&lt;/td&gt;
&lt;td&gt;"All generated images include a SynthID watermark"&lt;/td&gt;
&lt;td&gt;Verify watermarking behaviour on the target model before shipping regulated content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;response.generated_images[].image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;response.candidates[0].content.parts[].inline_data&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The gains are real. You get 4K output, which Imagen 4 did not offer through this API — its &lt;code&gt;imageSize&lt;/code&gt; topped out at &lt;code&gt;2K&lt;/code&gt;. You get interleaved text and image responses, which makes conversational editing possible in a way the predict-style endpoint did not. And you get a cheaper per-image floor via the lite model and the batch tier.&lt;/p&gt;

&lt;p&gt;The losses are mostly ergonomic. Losing &lt;code&gt;number_of_images&lt;/code&gt; is the one that touches real code, and the fan-out above closes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A twelve-day plan
&lt;/h2&gt;

&lt;p&gt;Twelve days from 5 August 2026. This is small enough to be done inside one sprint if it is started now.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Days&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Exit criteria&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Grep for &lt;code&gt;generate_images&lt;/code&gt;, &lt;code&gt;generateImages&lt;/code&gt;, &lt;code&gt;GenerateImages&lt;/code&gt;, &lt;code&gt;imagen-4.0&lt;/code&gt;, &lt;code&gt;generated_images&lt;/code&gt; and &lt;code&gt;:predict&lt;/code&gt; across every repository, notebook and scheduled job&lt;/td&gt;
&lt;td&gt;A list of call sites with an owner each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pull last month's image counts and resolutions from billing; decide the target model and tier per pipeline&lt;/td&gt;
&lt;td&gt;A written before/after cost estimate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2–4&lt;/td&gt;
&lt;td&gt;Swap the method and the response parsing; add the fan-out helper where &lt;code&gt;number_of_images&lt;/code&gt; was used; handle the &lt;code&gt;part.text&lt;/code&gt; branch&lt;/td&gt;
&lt;td&gt;Unit tests pass against the new response shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5–7&lt;/td&gt;
&lt;td&gt;Verify the parameters you relied on — aspect ratio, resolution, person generation, watermarking — against the image generation guide on the target model&lt;/td&gt;
&lt;td&gt;A parity checklist with a pass or an accepted difference per row&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8–10&lt;/td&gt;
&lt;td&gt;Run both paths side by side on a sample workload; compare output quality, latency and per-image cost&lt;/td&gt;
&lt;td&gt;Quality signed off by whoever owns the output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11–12&lt;/td&gt;
&lt;td&gt;Cut over, delete the Imagen path, and alert on any non-image response&lt;/td&gt;
&lt;td&gt;No &lt;code&gt;imagen-4.0&lt;/code&gt; string anywhere in the codebase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Also by 10 August&lt;/td&gt;
&lt;td&gt;Check for &lt;code&gt;embedding-2-preview&lt;/code&gt; usage — it shuts down that day, replaced by &lt;code&gt;gemini-embedding-2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Embedding calls confirmed on a supported model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last row is the one that catches people. Teams doing an image migration in the first half of August will not be looking at their embedding model, and &lt;code&gt;embedding-2-preview&lt;/code&gt; goes five days before Imagen does.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;For teams in Gurugram, Bengaluru, Pune and Hyderabad running image generation at volume for D2C catalogues, marketplace listings or ad creative, three points apply.&lt;/p&gt;

&lt;p&gt;The batch tier is the single largest saving available and it fits Indian catalogue workflows well. Product imagery for a listing refresh does not need a synchronous response. Moving that generation to batch takes a 1K image from $0.067 to $0.034, and at catalogue scale — tens of thousands of images per refresh cycle — that difference is the entire argument for scheduling the job overnight rather than generating on upload.&lt;/p&gt;

&lt;p&gt;Resolution discipline matters more here than in most markets, because marketplace and quick-commerce listing specs are modest. If your target surface renders at 1024px or below, generating at 4K and downsampling costs $0.151 instead of $0.067 for an asset nobody sees at full resolution.&lt;/p&gt;

&lt;p&gt;On governance, &lt;code&gt;personGeneration&lt;/code&gt; on Imagen 4 had a documented regional restriction — &lt;code&gt;"allow_all"&lt;/code&gt; was "not allowed in EU, UK, CH, MENA locations" — and any equivalent control on the target model needs to be verified rather than assumed, particularly if you generate imagery depicting people for campaigns that run across those regions. Where generated imagery is derived from customer photographs or user-submitted references, the Digital Personal Data Protection Act 2023 obligations attached to that source data follow it into the generation pipeline, so keep the reference store governed the same way as the rest of your customer data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern worth noticing
&lt;/h2&gt;

&lt;p&gt;This is the second image-model migration in roughly a year for anyone who was on Imagen 3, which the same documentation records as already shut down. The Gemini API deprecations page shows the cadence clearly: preview models routinely carry shutdown dates a few months out, and even GA models get them. &lt;code&gt;gemini-2.5-flash-image&lt;/code&gt;, released 2 October 2025, has a shutdown date exactly one year later.&lt;/p&gt;

&lt;p&gt;The practical response is architectural rather than tactical. Put the model ID in configuration, not in a call site. Wrap generation behind one function with a stable signature — the fan-out helper above is a start — so that the next deprecation is a config change and a parsing tweak rather than a search through six repositories. Teams that did this after the Imagen 3 shutdown will spend an afternoon on 17 August. Teams that did not will spend the week.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which Imagen models shut down on 17 August 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three of them: &lt;code&gt;imagen-4.0-generate-001&lt;/code&gt;, &lt;code&gt;imagen-4.0-ultra-generate-001&lt;/code&gt; and &lt;code&gt;imagen-4.0-fast-generate-001&lt;/code&gt;. All three were released on 24 June 2025 and all three carry the same 17 August 2026 shutdown date in the Gemini API deprecations table. Imagen 3's &lt;code&gt;imagen-3.0-generate-002&lt;/code&gt; was already shut down earlier, on 10 November 2025.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I migrate to gemini-2.5-flash-image or gemini-3.1-flash-image?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;. Google's Imagen guide page names &lt;code&gt;gemini-2.5-flash-image&lt;/code&gt;, but the deprecations table gives that model its own shutdown date of 2 October 2026. Migrating there means repeating this exercise 46 days later. The deprecations table names &lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;, which has no shutdown date announced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are the three code changes I have to make?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Call &lt;code&gt;client.models.generate_content&lt;/code&gt; instead of &lt;code&gt;client.models.generate_images&lt;/code&gt;. Read images from &lt;code&gt;response.candidates[0].content.parts&lt;/code&gt; by checking each part for &lt;code&gt;inline_data&lt;/code&gt;, rather than from &lt;code&gt;response.generated_images&lt;/code&gt;. And replace &lt;code&gt;number_of_images&lt;/code&gt;, which does not exist on Gemini image models, with your own fan-out because each call returns one image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does an image cost after migrating?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On &lt;code&gt;gemini-3.1-flash-image&lt;/code&gt;, image output bills at $60.00 per 1M tokens, which Google states as $0.045 per 0.5K image, $0.067 per 1K, $0.101 per 2K and $0.151 per 4K. The batch tier halves those figures, putting a 1K image at $0.034, and &lt;code&gt;gemini-3.1-flash-lite-image&lt;/code&gt; lists $0.0336 per 1K image on standard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the fan-out cost more than a single Imagen call did?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the output, no — you pay per image either way. For input, yes. One Imagen call with &lt;code&gt;number_of_images=4&lt;/code&gt; sent the prompt once; four Gemini calls send it four times, billed at $0.50 per 1M input tokens on the standard tier. That matters when the prompt carries long style instructions or reference images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What else in the Gemini API shuts down around the same time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two other models in the same window. &lt;code&gt;embedding-2-preview&lt;/code&gt; shuts down on 10 August 2026, with &lt;code&gt;gemini-embedding-2&lt;/code&gt; named as the replacement, and &lt;code&gt;gemini-robotics-er-1.6-preview&lt;/code&gt; shuts down on 31 August 2026, replaced by &lt;code&gt;gemini-robotics-er-2-preview&lt;/code&gt;. Both are easy to miss while you are auditing image generation code specifically, and the embedding one lands first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the 17 August date firm?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google's deprecations page notes that listed dates "indicate the earliest possible dates on which a model might be retired" and that it will communicate exact dates with advance notice. That is a softening in principle, not a reprieve. Treat 17 August 2026 as the deadline and plan for the endpoint being unavailable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I get anything back from this migration?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. 4K output becomes available, where Imagen 4's &lt;code&gt;imageSize&lt;/code&gt; supported only &lt;code&gt;1K&lt;/code&gt; and &lt;code&gt;2K&lt;/code&gt; and only on the Standard and Ultra models. Responses can interleave text with images, which makes conversational editing workflows possible. And the batch tier and the lite model both offer a lower per-image floor than the standard rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;We run image and model migrations like this one for teams that discovered the deadline late: inventory the call sites, model the per-image cost against your real resolution mix, swap the call and the parsing, and verify parameter parity before cutover rather than after. eCorpIT is CMMI Level 5 and ISO 27001:2022 certified, and our senior engineering teams design generation pipelines aligned with DPDP requirements. If 17 August is on your calendar without an owner, &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;talk to us&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Related reading: our &lt;a href="https://ecorpit.com/ai-image-generation-api-cost-comparison-2026/" rel="noopener noreferrer"&gt;AI image generation API cost comparison&lt;/a&gt; sets these rates against the other providers, the &lt;a href="https://ecorpit.com/nano-banana-2-vs-nano-banana-pro-production-image-model-2026/" rel="noopener noreferrer"&gt;Nano Banana 2 versus Nano Banana Pro production comparison&lt;/a&gt; covers model selection for production work, the &lt;a href="https://ecorpit.com/gemini-omni-flash-video-cost-marketing-teams-2026/" rel="noopener noreferrer"&gt;Gemini video generation cost guide&lt;/a&gt; applies the same per-token arithmetic to video, and the &lt;a href="https://ecorpit.com/gemini-3-5-pro-vs-gpt-5-6-vs-claude-fable-5-2026/" rel="noopener noreferrer"&gt;frontier model comparison&lt;/a&gt; is the pillar for this cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/deprecations" rel="noopener noreferrer"&gt;Gemini API deprecations (shutdown dates and recommended replacements) — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/imagen" rel="noopener noreferrer"&gt;Generate images using Imagen (deprecation banner, configuration parameters, code samples) — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/pricing" rel="noopener noreferrer"&gt;Gemini Developer API pricing — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/image-generation" rel="noopener noreferrer"&gt;Image generation guide — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/changelog" rel="noopener noreferrer"&gt;Gemini API release notes — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/api/generate-content" rel="noopener noreferrer"&gt;Generating content API reference — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aistudio.google.com/models/gemini-3-pro-image" rel="noopener noreferrer"&gt;Gemini 3.1 Flash Image in Google AI Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/docs/models" rel="noopener noreferrer"&gt;Gemini API models overview — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.googleblog.com/en/introducing-gemini-2-5-flash-image/" rel="noopener noreferrer"&gt;Introducing Gemini 2.5 Flash Image — Google Developers Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/ai-logic/generate-images-gemini" rel="noopener noreferrer"&gt;Generate and edit images using Gemini — Firebase AI Logic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/ai-logic/imagen-models-migration" rel="noopener noreferrer"&gt;Imagen models migration — Firebase AI Logic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ai.google.dev/gemini-api/terms" rel="noopener noreferrer"&gt;Gemini API terms of service — Google AI for Developers&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Last updated: 5 August 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>geminiapi</category>
      <category>imagen</category>
      <category>nanobanana</category>
      <category>imagegeneration</category>
    </item>
    <item>
      <title>OpenAI Assistants API shuts down 26 August 2026: a 3-week migration sprint plan</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 10:00:42 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/openai-assistants-api-shuts-down-26-august-2026-a-3-week-migration-sprint-plan-596b</link>
      <guid>https://dev.to/mr_manushukla/openai-assistants-api-shuts-down-26-august-2026-a-3-week-migration-sprint-plan-596b</guid>
      <description>&lt;h1&gt;
  
  
  OpenAI Assistants API shuts down 26 August 2026: a 3-week migration sprint plan
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; OpenAI removes the Assistants API on 26 August 2026, three weeks from today. The deprecation was announced on 26 August 2025 with a full year of notice, and OpenAI's documentation now files Assistants under "Legacy APIs" alongside Agent Builder, Evals and self-serve fine-tuning. The replacement is the Responses API plus the Conversations API, and the object mapping is short: Assistants become Prompts, Threads become Conversations, Runs become Responses, Run steps become Items. Two things about this migration are consistently underestimated. First, tool-call orchestration moves into your application code, OpenAI's own guide states that with Responses, "tool call loops are explicitly managed". Second, the cost shape changes even though the token rates do not: OpenAI's pricing page is explicit that "Responses API, Chat Completions API, Realtime API, Batch API, and Assistants API are not priced separately", yet file-search tool calls at $2.50 per 1,000 apply "to the Responses API only", and Code Interpreter has moved from a one-hour session to a 20-minute container billed from $0.03 to $1.92 depending on size. A workload that ran on 1-hour Code Interpreter sessions and heavy file search can cost meaningfully more after a like-for-like port. Three weeks is enough time to do this properly. It is not enough time to discover the cost change in your September invoice.&lt;/p&gt;

&lt;p&gt;There is also a trap in the recommended path. OpenAI tells you to recreate each Assistant as a reusable prompt object, and reusable prompt objects are themselves deprecated, with the &lt;code&gt;v1/prompts&lt;/code&gt; API scheduled to shut down on 30 November 2026. Migrating straight onto prompts means migrating onto a second deprecated object with a 96-day life.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is actually being removed, and when
&lt;/h2&gt;

&lt;p&gt;OpenAI's deprecations page records the sequence precisely: "On August 26th, 2025, we notified developers using the Assistants API of its deprecation and removal from the API one year later, on August 26, 2026." The migration guide repeats the date in a banner: "After achieving feature parity in the Responses API, we've deprecated the Assistants API. It will shut down on August 26, 2026."&lt;/p&gt;

&lt;p&gt;OpenAI's own definitions matter here, because "deprecated" and "shut down" are not the same thing on this platform. From the deprecations page: "We use the term 'deprecation' to refer to the process of retiring a model or endpoint… All deprecated models and endpoints will also have a shut down date. At the time of the shut down, the model or endpoint will no longer be accessible." And: "We use the terms 'sunset' and 'shut down' interchangeably to mean a model or endpoint is no longer accessible."&lt;/p&gt;

&lt;p&gt;The Assistants API has been deprecated for a year. On 26 August 2026 it becomes inaccessible. Any &lt;code&gt;client.beta.threads.*&lt;/code&gt; call in your codebase stops working on that date.&lt;/p&gt;

&lt;p&gt;The Assistants shutdown is one of five endpoint retirements OpenAI has scheduled across late 2026. The table below is the calendar worth putting on a wall, because teams often migrate off one of these and straight onto another.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint or platform&lt;/th&gt;
&lt;th&gt;Announced&lt;/th&gt;
&lt;th&gt;Shutdown&lt;/th&gt;
&lt;th&gt;Where it leaves you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Assistants API&lt;/td&gt;
&lt;td&gt;26 August 2025&lt;/td&gt;
&lt;td&gt;26 August 2026&lt;/td&gt;
&lt;td&gt;Responses API + Conversations API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reusable prompt objects (&lt;code&gt;v1/prompts&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3 June 2026&lt;/td&gt;
&lt;td&gt;30 November 2026&lt;/td&gt;
&lt;td&gt;Move prompt content into application code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evals dashboard and API&lt;/td&gt;
&lt;td&gt;3 June 2026&lt;/td&gt;
&lt;td&gt;30 November 2026 (read-only from 31 October 2026)&lt;/td&gt;
&lt;td&gt;No in-platform evals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Builder&lt;/td&gt;
&lt;td&gt;3 June 2026&lt;/td&gt;
&lt;td&gt;30 November 2026&lt;/td&gt;
&lt;td&gt;Agents SDK or ChatGPT Workspace Agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-serve fine-tuning platform&lt;/td&gt;
&lt;td&gt;,&lt;/td&gt;
&lt;td&gt;Winding down; closed to new users&lt;/td&gt;
&lt;td&gt;Fine-tuned models run until their base models are deprecated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read that table before you design your migration, not after. The path OpenAI's own migration guide recommends, recreate Assistants as dashboard prompts — lands you on a row that expires 96 days after the row you are escaping.&lt;/p&gt;

&lt;h2&gt;
  
  
  The object mapping
&lt;/h2&gt;

&lt;p&gt;OpenAI's migration guide gives the mapping directly:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;Now&lt;/th&gt;
&lt;th&gt;Why (OpenAI's stated reason)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Assistants&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Prompts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"Prompts hold configuration (model, tools, instructions) and are easier to version and update"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Threads&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Conversations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"Streams of items instead of just messages"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Runs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Responses&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"Responses send input items or use a conversation object and receive output items; tool call loops are explicitly managed"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Run steps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Items&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"Generalized objects—can be messages, tool calls, outputs, and more"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Messages&lt;/td&gt;
&lt;td&gt;Items (a subset)&lt;/td&gt;
&lt;td&gt;"Threads could only store messages. Conversations store items, which can include messages, tool calls, tool outputs, and other data"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the row that is not a rename. Runs to Responses changes who runs the loop. Under Assistants, a run entered &lt;code&gt;requires_action&lt;/code&gt;, you submitted tool outputs, and OpenAI resumed the run. Under Responses, as OpenAI puts it, "Your application code now handles orchestration (history pruning, tool loop, retries) while your prompt focuses on high-level behavior and constraints." That is the migration's real work item. Everything else is renaming.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code change
&lt;/h2&gt;

&lt;p&gt;The before-and-after in OpenAI's guide is unusually stark. Here is the polling shape you are removing:&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&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;assistant_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;assistant_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;queued&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;in_progress&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;thread_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;run_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the shape you are moving to:&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What are the 5 Ds of dodgeball?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation_id&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;Thread creation becomes conversation creation, with &lt;code&gt;messages&lt;/code&gt; becoming &lt;code&gt;items&lt;/code&gt;:&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="c1"&gt;# Before
&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what are the 5 Ds of dodgeball?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;peter_le_fleur&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# After
&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conversations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;what are the 5 Ds of dodgeball?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;peter_le_fleur&lt;/span&gt;&lt;span class="sh"&gt;"&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;In OpenAI's full chat-application example, a 34-line handler with a polling loop becomes a 17-line handler with one call. The response object carries &lt;code&gt;conversation&lt;/code&gt;, &lt;code&gt;previous_response_id&lt;/code&gt;, &lt;code&gt;store&lt;/code&gt; and &lt;code&gt;background&lt;/code&gt; fields; the guide notes that using a conversation object "lets you manage conversations instead of passing back &lt;code&gt;previous_response_id&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;One field disappears quietly and is worth checking for in your code. The thread object had &lt;code&gt;tool_resources&lt;/code&gt;; the conversation object in OpenAI's example does not. If you attached per-thread vector stores or Code Interpreter files through &lt;code&gt;tool_resources&lt;/code&gt;, that wiring has to be rebuilt on the Responses side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things the guide says you have to do by hand
&lt;/h2&gt;

&lt;p&gt;These are the items that turn a "rename some calls" estimate into a real sprint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assistants can no longer be created via API.&lt;/strong&gt; OpenAI is explicit: prompts "can only be created in the dashboard, where you can version them as you develop your product." If you provision assistants programmatically — one per tenant, one per workflow, one per customer — that pattern has no successor. OpenAI's suggested mitigation is to "Store the prompt ID (or its exported spec) in source control so application code can refer to a stable identifier" and to "run A/B tests by swapping prompt IDs—no need to create or delete assistant objects programmatically." For a single-tenant product that is fine. For a multi-tenant SaaS that spun up an assistant per customer, it is a redesign.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There is no automated thread migration.&lt;/strong&gt; In OpenAI's words: "We will not provide an automated tool for migrating Threads to Conversations. Instead, we recommend migrating new user threads onto conversations and migrating older ones as necessary." That implies a dual-path period where new sessions run on Conversations and old ones still read from Threads — and Threads stop existing on 26 August 2026, so any history you want to keep has to be copied before that date.&lt;/p&gt;

&lt;p&gt;The backfill script OpenAI publishes handles two content types:&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;for&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;item_content_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;item_content&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item_content_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
        &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;item_content&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_image&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;detail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}]&lt;/span&gt;

&lt;span class="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conversations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no &lt;code&gt;case&lt;/code&gt; for file attachments, tool outputs, or annotations. Citations from file search in historical threads are dropped by this script. If your product shows source citations on past conversations, extend the script or accept the loss knowingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The recommended target is deprecated.&lt;/strong&gt; The migration guide itself carries the warning: "Reusable prompt objects are also being deprecated. If you use this migration path, review the prompts deprecation timeline before adopting prompt objects in a long-lived integration." Our advice for anything with a life beyond this year: skip prompts, put instructions and tool schemas in your own code under version control, and pass them on each &lt;code&gt;responses.create&lt;/code&gt; call. You get the same versioning benefit from your existing Git history, and you do not repeat this exercise in November.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost changes nobody prices in
&lt;/h2&gt;

&lt;p&gt;OpenAI's pricing page states plainly that the API surface itself is not a billing dimension: "Responses API, Chat Completions API, Realtime API, Batch API, and Assistants API are not priced separately. Tokens are billed at the chosen model's input and output rates." So a straight port with the same model and the same token volume costs the same. Two tool lines are where the change hides.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost line&lt;/th&gt;
&lt;th&gt;Under Assistants&lt;/th&gt;
&lt;th&gt;Under Responses (as listed, August 2026)&lt;/th&gt;
&lt;th&gt;Effect of a like-for-like port&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model tokens&lt;/td&gt;
&lt;td&gt;Model rate&lt;/td&gt;
&lt;td&gt;Same model rate — for example &lt;code&gt;gpt-5.6-terra&lt;/code&gt; at $2.00 input / $12.00 output per 1M tokens&lt;/td&gt;
&lt;td&gt;Neutral&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File search storage&lt;/td&gt;
&lt;td&gt;$0.10 per GB per day, first GB free&lt;/td&gt;
&lt;td&gt;$0.10 per GB per day, first GB free&lt;/td&gt;
&lt;td&gt;Neutral&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File search tool calls&lt;/td&gt;
&lt;td&gt;Not billed as a separate line&lt;/td&gt;
&lt;td&gt;$2.50 per 1,000 calls — OpenAI notes this "applies to the Responses API only"&lt;/td&gt;
&lt;td&gt;New line item on every retrieval-heavy workload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Interpreter&lt;/td&gt;
&lt;td&gt;$0.03 per session, session active for one hour&lt;/td&gt;
&lt;td&gt;Container pricing: 1 GB $0.03, 4 GB $0.12, 16 GB $0.48, 64 GB $1.92 per 20-minute session, billed by the minute with a 5-minute minimum&lt;/td&gt;
&lt;td&gt;A one-hour working session now spans three 20-minute containers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data residency endpoints&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;10% uplift for models released on or after 5 March 2026 that are eligible for data residency&lt;/td&gt;
&lt;td&gt;Relevant if you pin processing to a region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fast mode&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Renamed from Priority processing on 30 July 2026; &lt;code&gt;service_tier: "priority"&lt;/code&gt; and &lt;code&gt;"fast"&lt;/code&gt; both accepted&lt;/td&gt;
&lt;td&gt;No action, but check hardcoded values&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Work the second and fourth rows against your own volumes before you commit to a design. A support assistant handling 200,000 retrieval-backed conversations a month, each making one file-search call, picks up a $500 monthly line that did not exist on the same workload under Assistants. And a data-analysis assistant whose users keep a Code Interpreter session alive for an hour was paying $0.03 for that hour; on the 1 GB container tier the same hour spans three sessions.&lt;/p&gt;

&lt;p&gt;The honest framing: for most chat workloads the migration is cost-neutral and the code gets shorter. For retrieval-heavy and Code Interpreter-heavy workloads, model the tool lines first. The right time to renegotiate an architecture is while you are already rewriting the call sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three-week sprint plan
&lt;/h2&gt;

&lt;p&gt;Twenty-one days from 5 August 2026 to the shutdown. This is the shape we would run it in.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Week&lt;/th&gt;
&lt;th&gt;Focus&lt;/th&gt;
&lt;th&gt;Exit criteria&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Week 1 (5–11 Aug)&lt;/td&gt;
&lt;td&gt;Inventory and decide. Grep for &lt;code&gt;beta.threads&lt;/code&gt;, &lt;code&gt;beta.assistants&lt;/code&gt;, &lt;code&gt;assistant_id&lt;/code&gt;, &lt;code&gt;requires_action&lt;/code&gt;, &lt;code&gt;submit_tool_outputs&lt;/code&gt;, &lt;code&gt;tool_resources&lt;/code&gt;. List every assistant, every tool it declares, every thread-retention promise made to users&lt;/td&gt;
&lt;td&gt;A written inventory with an owner and a decision per assistant: port, redesign, or retire&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 1&lt;/td&gt;
&lt;td&gt;Model the tool costs against last month's actual file-search call counts and Code Interpreter session durations&lt;/td&gt;
&lt;td&gt;A one-page before/after cost estimate signed off by whoever owns the bill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 2 (12–18 Aug)&lt;/td&gt;
&lt;td&gt;Rebuild. Move instructions and tool schemas into versioned application code; replace the run/poll loop with an explicit tool-call loop around &lt;code&gt;responses.create&lt;/code&gt;; rebuild &lt;code&gt;tool_resources&lt;/code&gt; attachments as Responses-side tool config&lt;/td&gt;
&lt;td&gt;The Responses path passes your existing test suite behind a feature flag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 2&lt;/td&gt;
&lt;td&gt;Write and dry-run the thread backfill against a copy, extending OpenAI's script for any content type you actually store&lt;/td&gt;
&lt;td&gt;Backfill completes on a sample tenant with item counts matching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 3 (19–25 Aug)&lt;/td&gt;
&lt;td&gt;Cut over by cohort, smallest first. Run backfill for threads you have promised to retain. Watch error rates, latency and tool-call counts daily&lt;/td&gt;
&lt;td&gt;Every cohort on Responses; no &lt;code&gt;beta.threads&lt;/code&gt; call in the last 48 hours of logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26 August 2026&lt;/td&gt;
&lt;td&gt;Shutdown day. Confirm zero traffic to the legacy path and no error spike&lt;/td&gt;
&lt;td&gt;Alerting green; legacy code deleted, not just disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two notes on sequencing. Do the cost model in week 1, not week 3 — if the numbers argue for changing the retrieval design, you want that decision before you rewrite the call sites, not after. And cut over by cohort rather than by feature flag percentage, because conversation state is per user: a user who flips mid-session between Threads and Conversations loses context.&lt;/p&gt;

&lt;p&gt;If you slip past 26 August, the failure is not graceful. Calls to a shut-down endpoint fail, and an assistant-backed feature in a production application fails with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;Three points for Indian teams and for engineering leaders in Gurugram, Bengaluru, Pune and Hyderabad running this migration for global customers.&lt;/p&gt;

&lt;p&gt;Data residency has a listed price now. OpenAI's pricing page states that "Regional processing (data residency) endpoints are charged a 10% uplift for models released on or after March 5, 2026, that are eligible for data residency." If your Digital Personal Data Protection Act 2023 posture, or a customer contract, requires regional processing, that uplift belongs in the migration cost model rather than arriving as a surprise. Teams should also note that OpenAI models served through Amazon Bedrock "are billed through AWS and may differ from direct OpenAI pricing", which changes the arithmetic if you route through a cloud marketplace for procurement reasons.&lt;/p&gt;

&lt;p&gt;Conversation storage is a data-governance decision, not just an API one. Conversations persist items server-side by default — the response object shows &lt;code&gt;"store": true&lt;/code&gt;. Under Assistants your threads were already server-side, so this is not new, but a migration is the natural moment to decide what you actually need retained, for how long, and whether transcripts belong in your own store instead. Teams handling health, financial or identity data should make that call deliberately.&lt;/p&gt;

&lt;p&gt;On staffing, three weeks is a sprint, and this work needs someone who has held the tool-call loop before. The orchestration that OpenAI used to run inside a run — retries, tool timeouts, partial failures, history pruning — is code you now own and have to get right under a deadline. This is the part where teams with no prior agent-loop experience lose a week.&lt;/p&gt;

&lt;h2&gt;
  
  
  What good looks like after the migration
&lt;/h2&gt;

&lt;p&gt;The end state is worth naming, because "it still works" is a low bar for a rewrite you were forced into.&lt;/p&gt;

&lt;p&gt;Instructions and tool schemas live in your repository, versioned with your application, not in a dashboard object with its own deprecation date. The tool-call loop is explicit, tested and instrumented, so a tool that starts timing out shows up on a dashboard rather than as a slow conversation. Retrieval calls are counted, because they are now billed. Conversation retention is a decision someone made, with a stated period. And the legacy path is deleted rather than flag-disabled, so nobody re-enables it in a rollback six months from now.&lt;/p&gt;

&lt;p&gt;That is a better system than the one you had. The migration is not optional, so the only real choice is whether you get that improvement out of it or just survive the date.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When exactly does the Assistants API stop working?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;26 August 2026. OpenAI notified developers on 26 August 2025 of the deprecation and removal one year later, and the migration guide repeats the date. On the shutdown date the endpoint becomes inaccessible, so calls to &lt;code&gt;client.beta.threads&lt;/code&gt; and related methods fail rather than degrade with warnings first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What replaces Assistants, Threads, Runs and Run steps?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assistants map to Prompts, Threads to Conversations, Runs to Responses, and Run steps to Items. OpenAI describes Items as "Generalized objects—can be messages, tool calls, outputs, and more". Conversations store items rather than only messages, so tool calls and outputs live alongside the message history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does migrating change what I pay per token?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. OpenAI's pricing page states that the Responses, Chat Completions, Realtime, Batch and Assistants APIs "are not priced separately" and that tokens bill at the chosen model's input and output rates. The changes are in tool pricing, specifically file-search tool calls and Code Interpreter container sessions, not in the model rates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which tool costs actually change?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two. File search tool calls are listed at $2.50 per 1,000 and OpenAI notes this pricing "applies to the Responses API only". Code Interpreter moves to container pricing: 1 GB at $0.03 through 64 GB at $1.92, per 20-minute session, billed by the minute with a five-minute minimum rather than the previous one-hour session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will OpenAI migrate my existing threads for me?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. The guide states directly that OpenAI "will not provide an automated tool for migrating Threads to Conversations" and recommends putting new threads on conversations while backfilling older ones as needed. OpenAI publishes a Python backfill script, but it handles only text and image content types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I recreate my assistants as reusable prompts?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Be careful. That is OpenAI's documented path, but reusable prompt objects are themselves deprecated, with the &lt;code&gt;v1/prompts&lt;/code&gt; API scheduled to shut down on 30 November 2026. For anything long-lived, put instructions and tool schemas into versioned application code instead and avoid running two migrations in one quarter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I still create assistants programmatically?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Prompts, the replacement configuration object, "can only be created in the dashboard" according to OpenAI's migration guide. Teams that provisioned one assistant per tenant or per workflow through the API need a different design, typically a single prompt or in-code configuration parameterised at request time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the biggest engineering change in the rewrite?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tool-call orchestration. OpenAI states that with Responses, "tool call loops are explicitly managed" and that "Your application code now handles orchestration (history pruning, tool loop, retries)". The polling loop around run status disappears, replaced by your own loop that dispatches tool calls and feeds outputs back into the next response.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT runs exactly this kind of deadline-bound migration: inventory the assistants and call sites, model the tool-cost change against your actual usage before any code moves, rebuild the tool loop with tests and instrumentation, and cut over by cohort with the backfill run against a copy first. Founded in 2021 and based in Gurugram, we are CMMI Level 5 and ISO 27001:2022 certified, and our senior engineering teams design AI systems aligned with DPDP requirements. Typical engagements here are a scoped three-week sprint with a named engineering lead, sized after a short discovery call. If 26 August is on your calendar without an owner, &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;talk to us&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Related reading: our &lt;a href="https://ecorpit.com/ecorpit-ai-agent-pilot-to-production-service-india-2026/" rel="noopener noreferrer"&gt;AI agent pilot to production service&lt;/a&gt; covers the orchestration and evaluation work this migration exposes, the &lt;a href="https://ecorpit.com/enterprise-ai-agents-production-use-cases-2026/" rel="noopener noreferrer"&gt;enterprise AI agents production guide&lt;/a&gt; is the pillar for this cluster, and the &lt;a href="https://ecorpit.com/openai-assistants-api-shutdown-responses-migration-2026/" rel="noopener noreferrer"&gt;Assistants API to Responses migration walkthrough&lt;/a&gt; and &lt;a href="https://ecorpit.com/azure-openai-assistants-api-foundry-agents-migration-2026/" rel="noopener noreferrer"&gt;Azure OpenAI Assistants to Foundry Agents guide&lt;/a&gt; cover the direct-OpenAI and Azure paths respectively. For teams reconsidering the model alongside the API, our &lt;a href="https://ecorpit.com/ecorpit-llm-migration-cost-optimization-service-india-2026/" rel="noopener noreferrer"&gt;LLM migration and cost optimization service&lt;/a&gt; covers the pricing analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/assistants/migration" rel="noopener noreferrer"&gt;Assistants migration guide (object mapping, code samples, backfill script) — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/deprecations" rel="noopener noreferrer"&gt;Deprecations — OpenAI API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;Pricing (model rates, tool pricing, data residency uplift) — OpenAI API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/assistants/deep-dive" rel="noopener noreferrer"&gt;Assistants API deep dive — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/api-reference/responses/create" rel="noopener noreferrer"&gt;Responses API reference — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/prompting/migrate-from-prompt-object" rel="noopener noreferrer"&gt;Migrate from prompt objects — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/agent-builder/migrate-from-agent-builder" rel="noopener noreferrer"&gt;Migrate from Agent Builder — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/your-data" rel="noopener noreferrer"&gt;Your data: regional processing and data residency — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/fast-mode" rel="noopener noreferrer"&gt;Fast mode (renamed from Priority processing, 30 July 2026) — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/amazon-bedrock" rel="noopener noreferrer"&gt;OpenAI models in Amazon Bedrock — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/tools-file-search" rel="noopener noreferrer"&gt;File search tool guide — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/tools-code-interpreter" rel="noopener noreferrer"&gt;Code Interpreter tool guide — OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/changelog" rel="noopener noreferrer"&gt;OpenAI API changelog&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Last updated: 5 August 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>openai</category>
      <category>assistantsapi</category>
      <category>responsesapi</category>
      <category>apimigration</category>
    </item>
    <item>
      <title>Bing SOAP and POX APIs retire 31 August 2026: the JSON migration checklist</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 09:54:37 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/bing-soap-and-pox-apis-retire-31-august-2026-the-json-migration-checklist-235m</link>
      <guid>https://dev.to/mr_manushukla/bing-soap-and-pox-apis-retire-31-august-2026-the-json-migration-checklist-235m</guid>
      <description>&lt;h1&gt;
  
  
  Bing SOAP and POX APIs retire 31 August 2026: the JSON migration checklist
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; Microsoft will stop serving the Bing Webmaster Tools SOAP and POX/HTTP endpoints on 31 August 2026, leaving JSON/HTTP as the only supported protocol. The notice published on Bing's help site is blunt: after that date, "requests to these endpoints will no longer be served." There is no throttling phase and no announced grace period. What survives the cutover is most of your integration — the same API key, the same daily ceiling of 10,000 submitted URLs per site, the same batch limit of 500 URLs per call, and the same method names. What breaks is the URL path, the XML request and response bodies, and any WCF service reference generated from the WSDL at &lt;code&gt;https://ssl.bing.com/webmaster/api.svc?wsdl&lt;/code&gt;. It follows a year of closures on the same platform: the Bing Search and Bing Custom Search APIs went dark on 11 August 2025, and PPC Land reported in June 2025 that the recommended replacement, Grounding with Bing Search, was listed at $35 per 1,000 transactions against the retiring S3 tier's $6 per 1,000. The Webmaster Tools API, by contrast, stays free. The only cost here is engineering time, and you have until 31 August 2026 to spend it.&lt;/p&gt;

&lt;p&gt;Most teams will find this is a two-hour change. The teams that will not are the ones running a C# client built through Visual Studio's "Add Service Reference" wizard, because that code is generated against the SOAP contract and has to be replaced rather than repointed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Microsoft actually announced
&lt;/h2&gt;

&lt;p&gt;The retirement was flagged in early August 2026 on Bing's official channels and picked up by Search Engine Roundtable on 3 August 2026. Krishna Madhavan, Principal Product Manager at Microsoft AI, Bing, posted the reminder:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"These legacy APIs will be retired on August 31, 2026. Please review the migration guidance and plan your move to our REST/JSON APIs."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The notice on the Bing Webmaster Tools help site carries the operative wording: "The SOAP and POX/HTTP APIs will be retired on August 31, 2026. After this date, requests to these endpoints will no longer be served. Migrate to the JSON/HTTP (REST) API before August 31, 2026 to avoid service interruption."&lt;/p&gt;

&lt;p&gt;Read "no longer be served" literally. A deprecation that degrades gracefully gives you a warning header, a 299 response, or a sunset window with rising error rates. This one is a switch. If your nightly indexing job still POSTs to &lt;code&gt;/webmaster/api.svc/pox/SubmitUrlBatch&lt;/code&gt; on 1 September 2026, it fails, and because most teams wrap URL submission in a fire-and-forget task, it may fail silently for weeks before anyone notices the drop in Bing-discovered pages.&lt;/p&gt;

&lt;p&gt;Note the wording: "plan your move", not "your calls will keep working". Microsoft's own guidance elsewhere has already shifted, which matters for step 4 below — for a large share of integrations the right answer is no longer "port the SOAP call to JSON".&lt;/p&gt;

&lt;h2&gt;
  
  
  What does not change
&lt;/h2&gt;

&lt;p&gt;Microsoft has been unusually specific about the parts of the contract that are stable. From the retirement notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every API method remains available over JSON/HTTP with identical functionality.&lt;/li&gt;
&lt;li&gt;Your existing API key continues to work. No re-issuance is required.&lt;/li&gt;
&lt;li&gt;Quotas, rate limits and permissions are unchanged.&lt;/li&gt;
&lt;li&gt;The JSON/HTTP endpoints continue to be supported and actively developed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the one worth internalising before you scope the work. This is not a platform migration in the sense that the Bing Search API shutdown was, where the replacement had a different data model, a different billing model and lived inside Azure. Here you are changing a path segment and a serialisation format against the same backend, the same account and the same key.&lt;/p&gt;

&lt;p&gt;The published quota behaviour is unchanged too. &lt;code&gt;GetUrlSubmissionQuota&lt;/code&gt; returns a &lt;code&gt;DailyQuota&lt;/code&gt; and &lt;code&gt;MonthlyQuota&lt;/code&gt; pair; Bing's own documentation example shows a response of &lt;code&gt;{"DailyQuota": 973, "MonthlyQuota": 10973}&lt;/code&gt;. The 10,000-URLs-per-day allowance introduced with the Adaptive URL Submission programme in January 2019 still governs, and &lt;code&gt;SubmitUrlBatch&lt;/code&gt; still caps at 500 URLs per request unless your remaining quota is lower.&lt;/p&gt;

&lt;h2&gt;
  
  
  The endpoint map: before and after
&lt;/h2&gt;

&lt;p&gt;Three protocols, one survivor. The table below is the substitution list to work through.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you call today&lt;/th&gt;
&lt;th&gt;What it becomes after 31 August 2026&lt;/th&gt;
&lt;th&gt;What else has to change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;https://ssl.bing.com/webmaster/api.svc/soap?apikey=API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://ssl.bing.com/webmaster/api.svc/json/METHOD_NAME?apikey=API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete the WCF service reference and the &lt;code&gt;system.serviceModel&lt;/code&gt; block in &lt;code&gt;app.config&lt;/code&gt;; replace the generated client with an HTTP client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;https://ssl.bing.com/webmaster/api.svc?wsdl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No equivalent — the JSON API has no WSDL&lt;/td&gt;
&lt;td&gt;Method signatures come from the API reference, not from code generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.../api.svc/pox/METHOD_NAME?apikey=…&amp;amp;param=VALUE&lt;/code&gt; (GET)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.../api.svc/json/METHOD_NAME?apikey=…&amp;amp;param=VALUE&lt;/code&gt; (GET)&lt;/td&gt;
&lt;td&gt;Parse JSON instead of XML; results arrive wrapped in a &lt;code&gt;d&lt;/code&gt; property&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.../api.svc/pox/METHOD_NAME?apikey=API_KEY&lt;/code&gt; (POST)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.../api.svc/json/METHOD_NAME?apikey=API_KEY&lt;/code&gt; (POST)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Content-Type: application/xml&lt;/code&gt; becomes &lt;code&gt;application/json&lt;/code&gt;; the XML body becomes a JSON object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POX fault: &lt;code&gt;&amp;lt;root type="object"&amp;gt;&amp;lt;ErrorCode type="number"&amp;gt;3&amp;lt;/ErrorCode&amp;gt;&amp;lt;Message&amp;gt;InvalidApiKey&amp;lt;/Message&amp;gt;&amp;lt;/root&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;JSON fault: &lt;code&gt;{"ErrorCode":3,"Message":"InvalidApiKey"}&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Error handling that regex-matches XML or catches &lt;code&gt;FaultException&amp;lt;ApiFault&amp;gt;&lt;/code&gt; has to be rewritten&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SOAP &lt;code&gt;FaultException&amp;lt;WebmasterApi.ApiFault&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;HTTP 400 with a JSON error body&lt;/td&gt;
&lt;td&gt;Exception-based control flow becomes status-code checking&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two details in that table cause most of the avoidable breakage.&lt;/p&gt;

&lt;p&gt;The first is the &lt;code&gt;d&lt;/code&gt; envelope. POX and JSON do not return the same shape. A &lt;code&gt;GetUrlSubmissionQuota&lt;/code&gt; call over JSON returns &lt;code&gt;{"d": {"__type": "UrlSubmissionQuota:#Microsoft.Bing.Webmaster.Api", "DailyQuota": 973, "MonthlyQuota": 10973}}&lt;/code&gt;. Code that reads &lt;code&gt;response["DailyQuota"]&lt;/code&gt; will throw a &lt;code&gt;KeyError&lt;/code&gt;; it needs &lt;code&gt;response["d"]["DailyQuota"]&lt;/code&gt;. Write-style calls such as &lt;code&gt;SubmitUrl&lt;/code&gt; and &lt;code&gt;SubmitUrlBatch&lt;/code&gt; return &lt;code&gt;{"d": null}&lt;/code&gt; on success, which is easy to mistake for a failure if your client treats a null payload as an error.&lt;/p&gt;

&lt;p&gt;The second is method-name casing. Bing's cURL guidance on the Webmaster blog uses &lt;code&gt;SubmitUrlBatch&lt;/code&gt;, while the JSON request sample on the Microsoft Learn reference page for the same method shows the path as &lt;code&gt;SubmitUrlbatch&lt;/code&gt; with a lowercase &lt;code&gt;b&lt;/code&gt;. The documentation is inconsistent. Test the exact string your client sends against a low-value URL before you cut over a production job, and log the response body rather than only the status code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: find every legacy call in your codebase
&lt;/h2&gt;

&lt;p&gt;Do this before you estimate the work. Legacy Bing calls hide in scheduled jobs, CMS plugins, deployment hooks and one-off scripts far more often than in application 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="c"&gt;# Endpoint paths, WSDL references and the generated SOAP client, in one pass&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rEn&lt;/span&gt; &lt;span class="s2"&gt;"api&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;svc/(soap|pox)|api&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;svc&lt;/span&gt;&lt;span class="se"&gt;\?&lt;/span&gt;&lt;span class="s2"&gt;wsdl|ssl&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;bing&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;com/webmaster"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'*.{py,js,ts,cs,php,rb,go,java,xml,config,json,yml,yaml,sh}'&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# The C# service-reference tell-tales, which grep for the endpoint alone will miss&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s2"&gt;"WebmasterApiClient&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;IWebmasterApi&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;BasicHttpBinding_IWebmasterApi"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then widen the search beyond the repository. Check your CI secrets and environment variables for a Bing API key (its presence tells you a job exists somewhere), your cron and scheduler definitions, any WordPress or Drupal SEO plugin that offers "submit to Bing", and any sitemap-generation step in your deploy pipeline. On a mid-sized publishing stack we would expect three to five call sites, not one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: rewrite the calls
&lt;/h2&gt;

&lt;p&gt;The JSON API is plain HTTP. Here is submission, batch submission and a quota check, first as shell commands you can paste to confirm your key works, then as production Python.&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="c"&gt;# Single URL&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://ssl.bing.com/webmaster/api.svc/json/SubmitUrl?apikey=API_KEY"&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;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"charset: utf-8"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"siteUrl":"https://www.example.com","url":"https://www.example.com/about"}'&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; {"d": null}&lt;/span&gt;

&lt;span class="c"&gt;# Batch (max 500 per call)&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://ssl.bing.com/webmaster/api.svc/json/SubmitUrlBatch?apikey=API_KEY"&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;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"charset: utf-8"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"siteUrl":"https://www.example.com","urlList":["https://www.example.com/about","https://www.example.com/projects"]}'&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; {"d": null}&lt;/span&gt;

&lt;span class="c"&gt;# Remaining quota&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://ssl.bing.com/webmaster/api.svc/json/GetUrlSubmissionQuota?siteUrl=https://www.example.com&amp;amp;apikey=API_KEY"&lt;/span&gt;
&lt;span class="c"&gt;# -&amp;gt; {"d":{"__type":"UrlSubmissionQuota:#Microsoft.Bing.Webmaster.Api","DailyQuota":973,"MonthlyQuota":10973}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bing's own guidance is explicit that cURL is for prototyping: use "a server-side script or application in your preferred language to handle authentication, batching, or error handling" in production. The Python below does the three things the shell version does not — it respects the batch ceiling, checks quota before spending it, and unwraps the &lt;code&gt;d&lt;/code&gt; envelope.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;

&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://ssl.bing.com/webmaster/api.svc/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;BATCH_MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;  &lt;span class="c1"&gt;# Microsoft's documented per-call ceiling
&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;qs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?apikey=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;qs&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;%s=%s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;safe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%s/%s%s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qs&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json; charset=utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;30&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;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# JSON API returns HTTP 400 with {"ErrorCode": n, "Message": "..."}
&lt;/span&gt;        &lt;span class="n"&gt;detail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bing %s failed: HTTP %s %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# unwrap the d envelope
&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remaining_daily_quota&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GetUrlSubmissionQuota&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;siteUrl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DailyQuota&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit_urls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;budget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;remaining_daily_quota&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;budget&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromkeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;))[:&lt;/span&gt;&lt;span class="n"&gt;budget&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# de-dupe, then clamp to quota
&lt;/span&gt;    &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;BATCH_MAX&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;BATCH_MAX&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nf"&gt;_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SubmitUrlBatch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;siteUrl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;site_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;urlList&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things that code does deliberately. It de-duplicates before clamping, because a batch of 500 containing 200 repeats burns 500 units of a 10,000-unit daily allowance for 300 useful submissions. And it raises on HTTP 400 with the response body attached, because &lt;code&gt;{"ErrorCode":3,"Message":"InvalidApiKey"}&lt;/code&gt; tells you exactly what went wrong while a bare &lt;code&gt;HTTPError: 400&lt;/code&gt; does not.&lt;/p&gt;

&lt;p&gt;If you are running the .NET client, delete the service reference rather than trying to repoint it. The generated &lt;code&gt;WebmasterApiClient&lt;/code&gt;, the &lt;code&gt;contract="WebmasterApi.IWebmasterApi"&lt;/code&gt; endpoint entry, and the &lt;code&gt;maxBufferSize&lt;/code&gt;/&lt;code&gt;maxReceivedMessageSize&lt;/code&gt; tuning that Microsoft's SOAP guide told you to raise to 524288 all become dead weight. &lt;code&gt;HttpClient&lt;/code&gt; plus &lt;code&gt;System.Text.Json&lt;/code&gt; replaces the lot in well under a hundred lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: fix authentication, and decide which of the two modes you need
&lt;/h2&gt;

&lt;p&gt;The Bing Webmaster API supports two authentication models, and they use different hosts. Getting this wrong produces a confusing 400 rather than a clear 401.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Endpoint host and auth&lt;/th&gt;
&lt;th&gt;When to use it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API key&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;https://ssl.bing.com/webmaster/api.svc/json/METHOD?apikey=KEY&lt;/code&gt; — the key travels in the query string&lt;/td&gt;
&lt;td&gt;Your own sites, verified under your own Bing Webmaster account; server-to-server jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth 2.0&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;https://www.bing.com/webmaster/api.svc/json/METHOD&lt;/code&gt; with &lt;code&gt;Authorization: Bearer &amp;lt;access_token&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Agencies and SaaS tools acting on a client's behalf, where the site owner grants delegated access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth scopes&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Webmaster.read&lt;/code&gt; for read access, &lt;code&gt;Webmaster.manage&lt;/code&gt; for read and write&lt;/td&gt;
&lt;td&gt;Request the narrower scope unless you actually submit URLs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token lifetimes&lt;/td&gt;
&lt;td&gt;Authorisation code valid for 5 minutes; access token returned with &lt;code&gt;expires_in&lt;/code&gt; of 3599 seconds&lt;/td&gt;
&lt;td&gt;Refresh tokens stay valid until the user revokes access — store them, or the client re-consents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credential source&lt;/td&gt;
&lt;td&gt;Client ID and secret from Bing Webmaster Tools, Settings, API Access&lt;/td&gt;
&lt;td&gt;The same screen generates the plain API key&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are on the API key path, the migration touches nothing about authentication. If you are on OAuth, note that the host in Microsoft's own &lt;code&gt;SubmitUrl&lt;/code&gt; example is &lt;code&gt;www.bing.com&lt;/code&gt;, not &lt;code&gt;ssl.bing.com&lt;/code&gt; — copying the API-key URL and bolting a bearer header onto it is a common failure.&lt;/p&gt;

&lt;p&gt;One security note worth acting on while you are in this code anyway: the API key sits in the query string, which means it lands in access logs, proxy logs and any error-tracking payload that captures request URLs. Scrub it in your logging middleware. Teams that treat this as an ordinary secret and only inject it at request time tend not to notice that it is being written to disk on every call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: decide whether to migrate the call at all
&lt;/h2&gt;

&lt;p&gt;This is the part a straight port misses. Microsoft added a note to its own cURL guide in November 2025 stating that it "now recommends using IndexNow as the primary method for real-time URL submission to Bing and participating search engines," describing the Adaptive URL Submission API as remaining "supported for advanced use cases and custom platform integrations."&lt;/p&gt;

&lt;p&gt;That is a meaningful reframing from the vendor that owns both. If the only thing your integration does is push new and updated URLs at Bing, IndexNow is the smaller surface: it is a flat POST with a key file on your own domain, it needs no Bing account credential in your deployment pipeline, and the same ping reaches other participating engines. If your integration also reads data — rank and traffic statistics, crawl issues, keyword data, verified site lists — the Webmaster API is the only route and you are migrating it regardless.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use case&lt;/th&gt;
&lt;th&gt;Adaptive URL Submission API (JSON)&lt;/th&gt;
&lt;th&gt;IndexNow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Submit new or changed URLs&lt;/td&gt;
&lt;td&gt;Yes, 10,000 per day per site, 500 per batch&lt;/td&gt;
&lt;td&gt;Yes, and the ping reaches participating engines beyond Bing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credential handling&lt;/td&gt;
&lt;td&gt;Bing API key or OAuth token in your pipeline&lt;/td&gt;
&lt;td&gt;A key file hosted on your own domain; no account secret in CI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read traffic, crawl and keyword data&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No — submission only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manage verified sites and users&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft's stated primary recommendation as of November 2025&lt;/td&gt;
&lt;td&gt;For advanced and custom platform integrations&lt;/td&gt;
&lt;td&gt;For real-time URL submission&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CMS plugin availability&lt;/td&gt;
&lt;td&gt;Limited; usually custom code&lt;/td&gt;
&lt;td&gt;Widely available across CMS platforms and plugins&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The honest read: most publishing teams should move URL submission to IndexNow and keep a slimmed JSON client only for the reporting calls they actually consume. A migration deadline is the cheapest moment to delete code you no longer need. If your Bing integration exists only because someone wired it up in 2019 and nobody has read its output since, the correct migration is deletion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: a cutover plan that fits the remaining window
&lt;/h2&gt;

&lt;p&gt;From 5 August 2026 you have 26 days. That is comfortable for a change of this size, and it is not comfortable if the work sits behind a release train with a two-week cadence.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Window&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Done when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Days 1–2&lt;/td&gt;
&lt;td&gt;Run the grep in step 1 across every repository, plus CI config, cron definitions and CMS plugins; list the call sites&lt;/td&gt;
&lt;td&gt;You have a written inventory with an owner per call site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 3–5&lt;/td&gt;
&lt;td&gt;For each call site, decide port, replace with IndexNow, or delete&lt;/td&gt;
&lt;td&gt;Each entry in the inventory has one of those three labels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 6–12&lt;/td&gt;
&lt;td&gt;Rewrite the ported calls against &lt;code&gt;/json/&lt;/code&gt;; verify each method name and response shape against a staging or low-value URL&lt;/td&gt;
&lt;td&gt;Every ported call returns a parsed &lt;code&gt;d&lt;/code&gt; payload in a test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 13–18&lt;/td&gt;
&lt;td&gt;Ship behind a feature flag; run legacy and JSON paths in parallel and compare submission counts and quota drawdown daily&lt;/td&gt;
&lt;td&gt;Counts match for three consecutive days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Days 19–24&lt;/td&gt;
&lt;td&gt;Remove the legacy path, the WSDL reference and any XML parsing helpers; add an alert on non-200 responses from the Bing client&lt;/td&gt;
&lt;td&gt;The old endpoint string appears nowhere in the codebase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;By 31 August 2026&lt;/td&gt;
&lt;td&gt;Confirm &lt;code&gt;GetUrlSubmissionQuota&lt;/code&gt; drawdown is still tracking daily&lt;/td&gt;
&lt;td&gt;Quota consumption on 1 September matches the previous week&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last row is the check most teams skip. The failure mode after a silent cutover is not an alert — it is a quota that stops being consumed, which looks like nothing at all on a dashboard nobody opens. An alert on "daily quota unchanged for 48 hours" catches it in two days rather than two months.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;Bing's share of search in India is small next to Google's, which is exactly why these integrations rot: nobody is watching the output closely enough to notice a 400. Three points for Indian teams specifically.&lt;/p&gt;

&lt;p&gt;For product and agency teams in Gurugram, Bengaluru and Hyderabad running submission jobs on behalf of overseas clients, the OAuth path is the correct one, not a shared API key pasted into a config file. A client-held key that a departing engineer still has is a genuine problem; a revocable delegated grant is not. The &lt;code&gt;Webmaster.read&lt;/code&gt; scope is enough for reporting-only integrations, and requesting &lt;code&gt;Webmaster.manage&lt;/code&gt; when you only read is a needless expansion of access.&lt;/p&gt;

&lt;p&gt;On data handling, the API key and any OAuth refresh token are credentials that let a third party act on a client's web property, so treat them with the same care as any production secret. The traffic and query reports you pull back can be joined to user-level analytics, and wherever that happens your existing posture under the Digital Personal Data Protection Act 2023 applies to the store you land them in. Design the pipeline so the raw pull lands in the same governed store as the rest of your search data rather than in an engineer's laptop notebook.&lt;/p&gt;

&lt;p&gt;On sequencing, teams supporting both Indian and international properties should migrate the lowest-traffic property first and watch quota drawdown for a full week before touching the flagship. The Bing account is per-site verified, so a mistake on a secondary property costs you nothing beyond the submissions you skipped that day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wider pattern: Microsoft is consolidating Bing's API surface
&lt;/h2&gt;

&lt;p&gt;This retirement is not an isolated tidy-up. Microsoft retired the Bing Search and Bing Custom Search APIs on 11 August 2025, announced only three months earlier on 12 May 2025, and the Azure notice made the scope clear: "Any existing instances of Bing Search APIs will be decommissioned completely, and the product will no longer be available for usage or new customer signup." The replacement, Grounding with Bing Search inside Azure AI Foundry, does not return raw results at all — as Microsoft's documentation states, "Developers and end users don't have access to raw content returned from Grounding with Bing Search."&lt;/p&gt;

&lt;p&gt;The cost shift there was steep. PPC Land's June 2025 analysis put Grounding with Bing Search at $35 per 1,000 transactions against retiring tiers of $6, $15 and $25 per 1,000, a 40% to 483% increase depending on which tier you were on.&lt;/p&gt;

&lt;p&gt;Against that backdrop, the Webmaster Tools change is the mild one: same key, same quotas, same price of zero, three months' notice, and a JSON endpoint that has existed alongside SOAP and POX since the API's early days. The direction of travel is still worth reading. Microsoft is narrowing Bing's programmatic surface to a small number of actively developed endpoints and pushing everything else toward either IndexNow or Azure. Integrations built on the oldest available protocol are the ones that keep getting caught. The real cost is usually the discovery, not the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What exactly is being retired on 31 August 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The SOAP and POX/HTTP protocols for the Bing Webmaster Tools API. Requests to the &lt;code&gt;api.svc/soap&lt;/code&gt; and &lt;code&gt;api.svc/pox&lt;/code&gt; paths, and the WSDL at &lt;code&gt;api.svc?wsdl&lt;/code&gt;, stop being served after that date. The JSON/HTTP endpoints at &lt;code&gt;api.svc/json&lt;/code&gt; continue and remain actively developed by Microsoft.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need a new API key after migrating?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Microsoft states that your API key remains the same and no re-issuance is required. Quotas, rate limits and permissions are also unchanged. The credential you use today against the POX endpoint works unmodified against the JSON endpoint, so the migration touches your request code rather than your secrets management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a grace period after 31 August 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Microsoft has announced none. The notice says requests to the SOAP and POX endpoints will no longer be served after that date, which reads as a hard cutoff rather than a throttling phase. Plan for calls to fail outright on 1 September 2026 rather than degrade with warnings first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What changes in the response body?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JSON responses wrap results in a &lt;code&gt;d&lt;/code&gt; property. A quota check returns &lt;code&gt;{"d":{"DailyQuota":973,"MonthlyQuota":10973}}&lt;/code&gt;, and a successful URL submission returns &lt;code&gt;{"d": null}&lt;/code&gt;. Errors arrive as HTTP 400 with a body such as &lt;code&gt;{"ErrorCode":3,"Message":"InvalidApiKey"}&lt;/code&gt; instead of a POX XML fault or a SOAP &lt;code&gt;FaultException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many URLs can I still submit per day?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The published limits are unchanged by this migration: 10,000 URLs per day per site under the Adaptive URL Submission programme, and a maximum of 500 URLs per &lt;code&gt;SubmitUrlBatch&lt;/code&gt; call unless your remaining quota is lower. Call &lt;code&gt;GetUrlSubmissionQuota&lt;/code&gt; first to read the current &lt;code&gt;DailyQuota&lt;/code&gt; before spending it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I move to IndexNow instead of migrating?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your integration only submits URLs, probably yes. Microsoft updated its own guidance in November 2025 to recommend IndexNow as the primary method for real-time URL submission, describing the Webmaster API as remaining supported for advanced and custom integrations. If you also read traffic, crawl or keyword data, you still need the JSON API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does OAuth 2.0 use a different endpoint than the API key?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, and this trips people up. API-key calls go to &lt;code&gt;ssl.bing.com&lt;/code&gt; with the key in the query string. Microsoft's OAuth example posts to &lt;code&gt;www.bing.com/webmaster/api.svc/json/SubmitUrl&lt;/code&gt; with an &lt;code&gt;Authorization: Bearer&lt;/code&gt; header. Access tokens are returned with an &lt;code&gt;expires_in&lt;/code&gt; of 3599 seconds and are renewed with the refresh token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the fastest way to find every affected call site?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Grep for &lt;code&gt;api.svc/soap&lt;/code&gt;, &lt;code&gt;api.svc/pox&lt;/code&gt; and &lt;code&gt;api.svc?wsdl&lt;/code&gt; across all of your repositories, then separately grep for &lt;code&gt;WebmasterApiClient&lt;/code&gt;, &lt;code&gt;IWebmasterApi&lt;/code&gt; and &lt;code&gt;BasicHttpBinding_IWebmasterApi&lt;/code&gt; to catch the generated .NET clients that never mention the endpoint URL at all. Extend the same search to your CI configuration, cron definitions and CMS SEO plugins.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;We run &lt;a href="https://ecorpit.com/ecorpit-api-integration-modernization-service-india-2026/" rel="noopener noreferrer"&gt;API integration modernization&lt;/a&gt; work for teams carrying exactly this kind of legacy surface — an integration nobody owns, built against a protocol the vendor is closing. Our senior engineering teams do the discovery pass across your repositories and pipelines, decide per call site whether to port, replace or delete, and ship the cutover behind a flag with parallel-run verification so nothing goes quiet unnoticed. eCorpIT is CMMI Level 5 and ISO 27001:2022 certified, and we design integrations aligned with DPDP requirements. If a 31 August deadline is sitting in your backlog without an owner, &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;talk to us&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Related reading: our &lt;a href="https://ecorpit.com/interop-2026-web-platform-developer-guide/" rel="noopener noreferrer"&gt;web platform developer guide&lt;/a&gt; covers the wider 2026 browser and API baseline, the &lt;a href="https://ecorpit.com/nextjs-16-migration-async-request-apis-cache-components-2026/" rel="noopener noreferrer"&gt;Next.js 16 migration guide&lt;/a&gt; walks a comparable framework cutover, and the &lt;a href="https://ecorpit.com/search-console-ai-performance-report-track-geo-visibility-2026/" rel="noopener noreferrer"&gt;Search Console AI performance report guide&lt;/a&gt; covers the Google-side reporting most teams pair with Bing data.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.seroundtable.com/bing-webmaster-tools-soap-pox-apis-retire-41805.html" rel="noopener noreferrer"&gt;Bing Webmaster Tools SOAP/POX APIs To Be Retired On August 31, 2026 — Search Engine Roundtable, 3 August 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/bingwebmaster/api-protocols" rel="noopener noreferrer"&gt;Bing Webmaster Tools API Services (supported protocols and URL formats) — Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/bingwebmaster/getting-started" rel="noopener noreferrer"&gt;Getting Started with Webmaster API (SOAP endpoint, WSDL, POX and JSON error samples) — Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/bingwebmaster/oauth2" rel="noopener noreferrer"&gt;Accessing Bing Webmaster APIs using OAuth 2.0 — Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.bing.webmaster.api.interfaces.iwebmasterapi.submiturlbatch?view=bing-webmaster-dotnet" rel="noopener noreferrer"&gt;IWebmasterApi.SubmitUrlBatch method (500-URL batch limit, JSON request and response samples) — Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.bing.webmaster.api.interfaces.iwebmasterapi.geturlsubmissionquota?view=bing-webmaster-dotnet" rel="noopener noreferrer"&gt;IWebmasterApi.GetUrlSubmissionQuota method — Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.bing.com/webmaster/november-2019/Accessing-Bing-webmaster-tools-api-using-cURL" rel="noopener noreferrer"&gt;Accessing Bing Webmaster Tools API using cURL (with the November 2025 IndexNow note) — Bing Webmaster Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.bing.com/webmaster/january-2019/bingbot-Series-Get-your-content-indexed-fast-by-now-submitting-up-to-10,000-URLs-per-day-to-Bing" rel="noopener noreferrer"&gt;bingbot Series: submitting up to 10,000 URLs per day to Bing — Bing Webmaster Blog, January 2019&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.bing.com/webmaster/may-2019/Easy-set-up-guide-for-Bing%E2%80%99s-Adaptive-URL-submission-API" rel="noopener noreferrer"&gt;Easy set-up guide for Bing's Adaptive URL submission API — Bing Webmaster Blog, May 2019&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ppc.land/microsoft-ends-bing-search-apis-on-august-11-alternative-costs-40-483-more/" rel="noopener noreferrer"&gt;Microsoft ends Bing Search APIs on August 11, alternative costs 40-483% more — PPC Land, 9 June 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.seroundtable.com/bing-search-apis-retiring-august-11-2025-39406.html" rel="noopener noreferrer"&gt;Bing Search APIs Retiring August 11, 2025 — Search Engine Roundtable, 14 May 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/foundry-classic/agents/how-to/tools-classic/bing-grounding" rel="noopener noreferrer"&gt;Grounding with Bing Search in Foundry Agent Service — Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bing.com/indexnow" rel="noopener noreferrer"&gt;IndexNow — Bing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/bingwebmaster/" rel="noopener noreferrer"&gt;Bing Webmaster API overview — Microsoft Learn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ppc.land/microsoft-expands-bing-webmaster-tools-data-capabilities-to-24-months/" rel="noopener noreferrer"&gt;Microsoft expands Bing Webmaster Tools data capabilities to 24 months (Krishna Madhavan's role at Microsoft AI, Bing) — PPC Land&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Last updated: 5 August 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bingwebmastertools</category>
      <category>apimigration</category>
      <category>indexnow</category>
      <category>technicalseo</category>
    </item>
    <item>
      <title>The 2026 cost of digital marketing in Gurugram: pricing bands and what AI search changed</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 01:18:12 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/the-2026-cost-of-digital-marketing-in-gurugram-pricing-bands-and-what-ai-search-changed-550g</link>
      <guid>https://dev.to/mr_manushukla/the-2026-cost-of-digital-marketing-in-gurugram-pricing-bands-and-what-ai-search-changed-550g</guid>
      <description>&lt;h1&gt;
  
  
  The 2026 cost of digital marketing in Gurugram: pricing bands and what AI search changed
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; A full-service digital marketing retainer in Gurugram and the wider Delhi-NCR market runs from about Rs 50,000 to Rs 5,00,000 a month in 2026, with premium performance mandates quoted at Rs 4,00,000 to Rs 10,00,000 and above. Standalone SEO sits between Rs 8,000 and Rs 80,000 a month, social media management between Rs 12,000 and Rs 2,00,000, and most agencies bill Google Ads management at 10% to 15% of ad spend with the media budget always separate. Published guides put Delhi NCR 20% to 35% above other Indian cities for the same scope. The price is only half the decision this year. SparkToro's analysis of Similarweb clickstream data found that 68.01% of US Google searches ended without a click in the first four months of 2026, up from 60.45% in 2024, a jump of 7.56 percentage points in two years. For every 1,000 US Google searches, 276 clicks now reach the open web, against 374 in 2024. AI Overviews appear on more than 20% of searches and cut click-through by nearly 60% where they appear. Ranking alone no longer pays for itself. What still pays, and this matters more in Gurugram than almost anywhere, is branded, local and high-intent transactional search. This guide sets out the current bands, explains why published guides disagree so wildly, and defines what a retainer at each level should actually deliver.&lt;/p&gt;

&lt;h2&gt;
  
  
  What digital marketing costs in Gurugram in 2026
&lt;/h2&gt;

&lt;p&gt;The bands below are compiled from Indian agency pricing guides published in 2026. Gurugram sits at the mid-to-upper end because local salary levels and demand run higher than in smaller cities.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Typical 2026 monthly cost (NCR)&lt;/th&gt;
&lt;th&gt;What it usually includes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Local SEO&lt;/td&gt;
&lt;td&gt;Rs 10,000 to Rs 40,000&lt;/td&gt;
&lt;td&gt;Google Business Profile, Maps, on-page, local citations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full SEO&lt;/td&gt;
&lt;td&gt;Rs 8,000 to Rs 80,000&lt;/td&gt;
&lt;td&gt;Technical, content, links, and now GEO and AEO work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Social media&lt;/td&gt;
&lt;td&gt;Rs 12,000 to Rs 2,00,000&lt;/td&gt;
&lt;td&gt;Content, community, paid social management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Ads management&lt;/td&gt;
&lt;td&gt;10% to 15% of ad spend&lt;/td&gt;
&lt;td&gt;Setup, optimisation, reporting; ad spend is separate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content marketing&lt;/td&gt;
&lt;td&gt;Rs 20,000 to Rs 1,00,000&lt;/td&gt;
&lt;td&gt;Strategy, articles, landing assets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full-service retainer&lt;/td&gt;
&lt;td&gt;Rs 50,000 to Rs 5,00,000 and above&lt;/td&gt;
&lt;td&gt;SEO, ads, social and content combined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premium performance mandate&lt;/td&gt;
&lt;td&gt;Rs 4,00,000 to Rs 10,00,000 and above&lt;/td&gt;
&lt;td&gt;Multi-channel, senior team, revenue-linked reporting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Within those ranges, the commonly quoted NCR tiers are around Rs 25,000 a month for basic social media management, Rs 50,000 for comprehensive digital marketing including SEO and content, and Rs 75,000 and above for full-funnel work including paid advertising. A mid-tier package covering SEO, Google Ads management and social typically lands at Rs 40,000 to Rs 80,000.&lt;/p&gt;

&lt;p&gt;Two numbers get missed when founders compare quotes.&lt;/p&gt;

&lt;p&gt;The first is the NCR premium. Published guides put Delhi NCR at 20% to 35% above other Indian cities for the same scope, which is a salary and demand effect rather than a quality one. A Rs 60,000 Gurugram retainer and a Rs 45,000 Indore retainer may be buying similar seniority.&lt;/p&gt;

&lt;p&gt;The second is ad spend, which sits on top of the management fee. Budget the true monthly total as retainer plus ad spend plus tools and creative, never the retainer alone. Our &lt;a href="https://ecorpit.com/ppc-advertising-gurugram-google-ads-roi-2026/" rel="noopener noreferrer"&gt;Gurugram Google Ads and PPC ROI guide&lt;/a&gt; works through that arithmetic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why published pricing guides disagree so much
&lt;/h2&gt;

&lt;p&gt;Worth saying plainly, because it changes how you should read any pricing article including this one: no authoritative body publishes agency rate cards in India. There is no industry survey with a disclosed methodology, no regulator collecting the data, and no trade association benchmark.&lt;/p&gt;

&lt;p&gt;What exists is agency blogs quoting their own bands, and they are not independent. That is why one guide will tell you SEO starts at Rs 8,000 and another will start it at Rs 15,000, and why management fees appear as 10% to 15% in one place and 15% to 20% in another. Both are describing real quotes; neither is describing the market.&lt;/p&gt;

&lt;p&gt;The practical consequence is that ranges are useful for sanity-checking a quote and useless for negotiating one. If a proposal sits inside the bands above, the number is not the thing to argue about. The scope is.&lt;/p&gt;

&lt;p&gt;One judgement from doing this work: the spread between two Gurugram quotes for nominally the same service is usually explained by how many hours of senior time are in the retainer, and that is the single question most buyers never ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  What drives the price
&lt;/h2&gt;

&lt;p&gt;Four things move a Gurugram quote.&lt;/p&gt;

&lt;p&gt;Scope is the obvious one. A single channel costs a fraction of a full-service retainer, and most of the very low numbers you see quoted are single-channel.&lt;/p&gt;

&lt;p&gt;Seniority is the quiet one. A team including a strategist and a technical SEO lead costs more than one junior working through a checklist, and it usually returns more. Ask how many hours a month a senior person is actually on your account, and ask for that in the contract.&lt;/p&gt;

&lt;p&gt;Deliverable depth is the 2026 one. It means whether the work includes AI-search optimisation or stops at traditional SEO. A Rs 10,000 retainer chasing keyword rankings is cheap for a reason, and in the current search environment it can return very little.&lt;/p&gt;

&lt;p&gt;Reporting is the one that determines whether you can tell any of this. A retainer that reports rankings only cannot demonstrate return, which means you cannot judge whether the other three were worth the money.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI search changed, with the numbers
&lt;/h2&gt;

&lt;p&gt;Search moved under the agency's feet, and the data is now unambiguous enough to plan around.&lt;/p&gt;

&lt;p&gt;SparkToro, using Similarweb desktop and mobile web panel data covering US Google searches from January to April 2026, found 68.01% of searches ended without a click. The 2024 figure was 60.45%, so the zero-click rate rose 7.56 percentage points in two years. Expressed as traffic rather than percentage, 1,000 US Google searches now send 276 clicks to the open web, down from 374 in 2024.&lt;/p&gt;

&lt;p&gt;Mobile is worse, approaching 77% zero-click. Since mobile is roughly two-thirds of searches, the mobile figure is closer to what most Indian brands see in their analytics than the headline number.&lt;/p&gt;

&lt;p&gt;AI Overviews appear on more than 20% of Google searches and, where present, cut click-through by nearly 60%.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;2024&lt;/th&gt;
&lt;th&gt;Early 2026&lt;/th&gt;
&lt;th&gt;Direction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Zero-click share of US Google searches&lt;/td&gt;
&lt;td&gt;60.45%&lt;/td&gt;
&lt;td&gt;68.01%&lt;/td&gt;
&lt;td&gt;Up 7.56 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clicks to the open web per 1,000 searches&lt;/td&gt;
&lt;td&gt;374&lt;/td&gt;
&lt;td&gt;276&lt;/td&gt;
&lt;td&gt;Down 98 clicks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile zero-click share&lt;/td&gt;
&lt;td&gt;Not stated in the study&lt;/td&gt;
&lt;td&gt;Approaching 77%&lt;/td&gt;
&lt;td&gt;Worse than desktop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Overview presence&lt;/td&gt;
&lt;td&gt;Lower&lt;/td&gt;
&lt;td&gt;More than 20% of searches&lt;/td&gt;
&lt;td&gt;Growing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CTR where an AI Overview appears&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;td&gt;Down nearly 60%&lt;/td&gt;
&lt;td&gt;Sharp drop&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note the scope honestly: this is US clickstream data. No equivalent India panel study has been published, so treat it as directionally true for Indian search rather than precisely so.&lt;/p&gt;

&lt;p&gt;The upside is real rather than purely defensive. Pages quoted inside an AI Overview earn substantially more organic clicks per impression than uncited pages on the same query, which is why citation share has become a target rather than a curiosity. Getting cited is a growth strategy now, not damage control.&lt;/p&gt;

&lt;h2&gt;
  
  
  The exception that matters most in Gurugram
&lt;/h2&gt;

&lt;p&gt;Here is the part that pricing guides skip and that changes the calculation for a local business.&lt;/p&gt;

&lt;p&gt;Rand Fishkin, co-founder of SparkToro, pointed specifically to branded, local and high-intent transactional searches as the areas where SEO still generates meaningful returns. He also made the broader point directly: "your SEO still matters as much or more than ever before, it just won't earn you traffic the way it once did."&lt;/p&gt;

&lt;p&gt;Read that against a Gurugram client list. A dental clinic in Sector 56, a chartered accountancy practice, an interior contractor, a preschool, a car service centre: their most valuable queries are local and transactional, and those are the queries an AI Overview is least likely to answer outright. Someone searching for a service they intend to buy this week still clicks.&lt;/p&gt;

&lt;p&gt;So the zero-click number is a reason to reallocate, not to disinvest. For a local Gurugram business, the money that used to fund broad informational content is better spent on Google Business Profile, Maps visibility, review volume and quality, service-page depth, and conversion tracking that proves a call turned into a job. Our &lt;a href="https://ecorpit.com/local-seo-gurugram-google-maps-rankings-2026/" rel="noopener noreferrer"&gt;Gurugram local SEO and Google Maps guide&lt;/a&gt; covers that work in detail.&lt;/p&gt;

&lt;p&gt;For a business selling nationally or globally out of Gurugram, the opposite applies: informational content still matters, but it has to be written to be quoted, which is what generative engine optimisation and answer engine optimisation mean in practice. Our &lt;a href="https://ecorpit.com/content-marketing-agency-gurugram-strategy-2026/" rel="noopener noreferrer"&gt;content marketing strategy for Gurugram brands&lt;/a&gt; shows what answer-shaped content looks like.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a retainer should deliver, band by band
&lt;/h2&gt;

&lt;p&gt;Bands are only useful if you know what each should buy. This is what we would consider a fair scope at each level in Gurugram in 2026.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Monthly retainer&lt;/th&gt;
&lt;th&gt;Realistic scope&lt;/th&gt;
&lt;th&gt;What it should not promise&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rs 10,000 to Rs 25,000&lt;/td&gt;
&lt;td&gt;One channel, executional: social posting or Google Business Profile upkeep&lt;/td&gt;
&lt;td&gt;Technical SEO, GEO or AEO work, or measurable organic growth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rs 25,000 to Rs 60,000&lt;/td&gt;
&lt;td&gt;Local SEO plus one more channel, basic technical fixes, monthly reporting&lt;/td&gt;
&lt;td&gt;National-scale organic growth or complex content programmes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rs 60,000 to Rs 1,50,000&lt;/td&gt;
&lt;td&gt;Technical audit, keyword-led content plan, outreach links, ads management, citation tracking&lt;/td&gt;
&lt;td&gt;Same-quarter revenue transformation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rs 1,50,000 to Rs 5,00,000&lt;/td&gt;
&lt;td&gt;Multi-channel with senior strategy, GEO and AEO in core scope, CRO, revenue-linked reporting&lt;/td&gt;
&lt;td&gt;Guaranteed rankings, which nobody can promise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rs 4,00,000 and above&lt;/td&gt;
&lt;td&gt;Full-funnel performance mandate, dedicated senior team, attribution modelling&lt;/td&gt;
&lt;td&gt;A fixed cost per lead independent of market conditions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If a proposal sits in one band and promises the outcomes of the band above, that is the signal to slow down.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to evaluate a Gurugram agency in 2026
&lt;/h2&gt;

&lt;p&gt;Ask five questions before you sign.&lt;/p&gt;

&lt;p&gt;Is GEO and AEO inside the scope, or does the SEO stop at keywords and links? In 2026 these belong in the core scope, not as paid add-ons.&lt;/p&gt;

&lt;p&gt;How many hours of senior time are on my account each month, and can that go in the contract?&lt;/p&gt;

&lt;p&gt;How do you report return, and does the reporting connect to leads and revenue rather than rankings?&lt;/p&gt;

&lt;p&gt;Is ad spend separated from the management fee in writing?&lt;/p&gt;

&lt;p&gt;What happens in month one, and what is the first thing you would fix? An agency that has looked at your site before pitching will answer this specifically.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Reassuring answer&lt;/th&gt;
&lt;th&gt;Warning sign&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;GEO and AEO named in the core deliverables&lt;/td&gt;
&lt;td&gt;"We can add AI search optimisation later"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reporting&lt;/td&gt;
&lt;td&gt;Leads, qualified traffic, citation share, cost per acquisition&lt;/td&gt;
&lt;td&gt;A monthly keyword ranking screenshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ad spend&lt;/td&gt;
&lt;td&gt;Separated from the fee, in the proposal&lt;/td&gt;
&lt;td&gt;A single blended number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Guarantees&lt;/td&gt;
&lt;td&gt;Forecasts with assumptions stated&lt;/td&gt;
&lt;td&gt;Guaranteed first-page rankings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team&lt;/td&gt;
&lt;td&gt;Named senior owner with committed hours&lt;/td&gt;
&lt;td&gt;"You will have a dedicated account manager"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a wider view of the local market, our guide to the &lt;a href="https://ecorpit.com/best-digital-marketing-company-gurugram-2026/" rel="noopener noreferrer"&gt;best digital marketing company in Gurugram&lt;/a&gt; sets out what strong local agencies now offer, and &lt;a href="https://ecorpit.com/digital-marketing-agency-delhi-ncr-gurugram-2026/" rel="noopener noreferrer"&gt;why Delhi NCR businesses hire Gurugram agencies&lt;/a&gt; covers the regional dynamics.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;Three local factors change the maths.&lt;/p&gt;

&lt;p&gt;GST applies on top. Agency retainers attract GST, so a Rs 1,00,000 retainer is not a Rs 1,00,000 cash outflow. Confirm whether quoted numbers are inclusive or exclusive before you compare two proposals.&lt;/p&gt;

&lt;p&gt;The talent market sets the floor. The NCR premium exists because senior marketing and technical SEO salaries in Gurugram are higher than in most Indian cities. A retainer well below the local bands is usually being staffed by juniors or offshore, and that is a legitimate choice as long as you know you are making it.&lt;/p&gt;

&lt;p&gt;Local intent is your advantage, not your constraint. Gurugram businesses serving Gurugram customers are sitting in the query category that survived the zero-click shift best. Founders reading national zero-click statistics and concluding that SEO is finished are drawing the wrong conclusion from the right data.&lt;/p&gt;

&lt;p&gt;Early-stage companies weighing whether to spend at all should read our &lt;a href="https://ecorpit.com/digital-marketing-startups-gurugram-guide-2026/" rel="noopener noreferrer"&gt;no-BS guide for Gurugram startups&lt;/a&gt; alongside this one, and teams choosing a social partner should see &lt;a href="https://ecorpit.com/social-media-marketing-agency-gurugram-results-2026/" rel="noopener noreferrer"&gt;how to pick a Gurugram social media agency that delivers results&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How much does digital marketing cost in Gurugram in 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A full-service retainer runs from about Rs 50,000 to Rs 5,00,000 a month, with premium performance mandates quoted at Rs 4,00,000 to Rs 10,00,000 and above. Standalone SEO is Rs 8,000 to Rs 80,000, social media Rs 12,000 to Rs 2,00,000, and Google Ads management is usually 10% to 15% of ad spend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is Gurugram more expensive than other Indian cities?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Published pricing guides put Delhi NCR at 20% to 35% above other Indian cities for the same scope. The gap reflects local salary levels and demand rather than a difference in quality, so a Gurugram retainer and a smaller-city retainer at different prices may be buying comparable seniority.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do published pricing guides disagree with each other?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because no authoritative body publishes agency rate cards in India. There is no industry survey with a disclosed methodology and no trade association benchmark, so the available figures come from agency blogs quoting their own bands. Use ranges to sanity-check a quote, not to negotiate one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is cheap SEO still worth buying in 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rarely, if it only chases rankings. SparkToro found 68.01% of US Google searches ended without a click in early 2026, and AI Overviews cut click-through by nearly 60% where they appear. A low retainer that produces keyword reports and low-quality links returns very little in that environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the zero-click data mean SEO is finished for local businesses?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No, and Gurugram businesses are the clearest exception. SparkToro's Rand Fishkin named branded, local and high-intent transactional searches as the areas where SEO still generates meaningful returns. Someone searching for a service they intend to buy this week still clicks through to a provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are GEO and AEO, and should they be in my retainer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GEO is generative engine optimisation and AEO is answer engine optimisation. Both shape content so AI systems and Google AI Overviews quote it rather than paraphrasing it away. In 2026 they belong in the core agency scope alongside technical SEO, because citations now drive a meaningful share of qualified visibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is ad spend included in the agency fee?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Almost every Gurugram agency bills Google Ads management as a flat fee or 10% to 15% of ad spend, with the media budget paid separately to Google. Budget the true monthly total as retainer plus ad spend plus tools and creative, and ask for that split in writing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What should a 2026 agency report to me?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reporting that ties to revenue: qualified and converting traffic, citation share inside AI Overviews, leads and cost per acquisition. Rankings still matter, but with 276 clicks reaching the open web per 1,000 searches against 374 in 2024, rankings alone no longer predict traffic or return.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT is a Gurugram-based, senior-led digital marketing and engineering organisation, founded in 2021, assessed at CMMI Level 5, MSME certified and ISO 27001:2022 certified, and a Google partner. We build SEO, GEO and AEO into one scope so content ranks and gets cited, we keep ad spend separate from management fees in every proposal, and we report on qualified traffic, citations and leads rather than rankings. If you are comparing digital marketing quotes in Gurugram and want a second opinion on the scope rather than the number, &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;talk to our team&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://sparktoro.com/blog/in-2026-less-than-one-third-of-google-searches-still-send-a-click" rel="noopener noreferrer"&gt;In 2026, less than one third of Google searches still send a click&lt;/a&gt; - SparkToro&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://searchengineland.com/google-zero-click-searches-2026-study-479717" rel="noopener noreferrer"&gt;Google zero-click searches reach 68% in early 2026: Study&lt;/a&gt; - Search Engine Land&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.seroundtable.com/google-zero-click-searches-fall-41475.html" rel="noopener noreferrer"&gt;Google Zero Click Searches Fall To 27.6%&lt;/a&gt; - Search Engine Roundtable&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalapplied.com/blog/sparktoro-zero-click-study-2026-68-percent-seo-analysis" rel="noopener noreferrer"&gt;Zero-Click Hits 68%: Inside the 2026 SparkToro Study&lt;/a&gt; - Digital Applied&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalapplied.com/blog/zero-click-search-statistics-2026-complete-data" rel="noopener noreferrer"&gt;Zero-click search statistics 2026&lt;/a&gt; - Digital Applied&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.relevantaudience.com/seo/google-zero-click-hit-68-percent-in-2026/" rel="noopener noreferrer"&gt;Zero-Click Searches Hit 68%: What This Means for SEO and AI Search in 2026&lt;/a&gt; - Relevant Audience&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://distk.in/blog/digital-marketing-agency-cost-india-2026.html" rel="noopener noreferrer"&gt;Digital marketing agency cost in India 2026&lt;/a&gt; - Distk&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://theconversions.com/blog/digital-marketing-cost-india" rel="noopener noreferrer"&gt;Digital marketing cost in India 2026: real price ranges by service&lt;/a&gt; - The Conversions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://adservex.digital/blog/digital-marketing-agency-pricing-india-2026" rel="noopener noreferrer"&gt;Digital marketing agency pricing in India 2026&lt;/a&gt; - Adservex&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.mayankdigitallabs.in/blog/digital-marketing-cost-india-2026" rel="noopener noreferrer"&gt;Digital marketing cost India 2026: complete pricing guide&lt;/a&gt; - Mayank Digital Labs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://digitalupgrowth.com/digital-marketing-agency-pricing-what-to-expect-in-2026/" rel="noopener noreferrer"&gt;Digital marketing agency pricing guide 2026&lt;/a&gt; - Digital Upgrowth&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://c2creview.co/articles/digital-marketing-agency-pricing-in-india-a-complete-2026-cost-guide" rel="noopener noreferrer"&gt;Digital marketing agency pricing in India: a complete 2026 cost guide&lt;/a&gt; - C2C Review&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last updated: 5 August 2026.&lt;/p&gt;

</description>
      <category>digitalmarketing</category>
      <category>gurugram</category>
      <category>pricing</category>
      <category>seo</category>
    </item>
    <item>
      <title>Product schema in 2026: 9 fixes that decide if your merchant listings show</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 01:12:58 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/product-schema-in-2026-9-fixes-that-decide-if-your-merchant-listings-show-16cm</link>
      <guid>https://dev.to/mr_manushukla/product-schema-in-2026-9-fixes-that-decide-if-your-merchant-listings-show-16cm</guid>
      <description>&lt;h1&gt;
  
  
  Product schema in 2026: 9 fixes that decide if your merchant listings show
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; On 7 July 2026 Google made two changes to merchant listing structured data. It added a &lt;code&gt;category&lt;/code&gt; property to &lt;code&gt;Product&lt;/code&gt;, which lets you declare a Google Product Category in page markup instead of only in a Merchant Center feed, and it added a new "Sale duration" section explaining how &lt;code&gt;validFrom&lt;/code&gt;, &lt;code&gt;validThrough&lt;/code&gt; and &lt;code&gt;priceValidUntil&lt;/code&gt; set the effective window for a sale price. Both changes close a gap between what your page says and what your feed says. The timing is not accidental: Q3 and Q4 promotional calendars run on sale windows, and Google's documentation now states plainly that "Your listing may not display if the &lt;code&gt;priceValidUntil&lt;/code&gt; property indicates a past date." For Indian sellers the stakes scale with the market. The India Brand Equity Foundation puts India's e-commerce industry at Rs 10,82,875 crore (US$ 125 billion) in 2024, projected to Rs 29,88,735 crore (US$ 345 billion) by 2030 at an 18.4% CAGR, with online shoppers rising from 280 to 300 million in 2025 towards 420 to 440 million by 2030. In our remediation work the new properties are rarely the reason a page loses rich results. Older rules are: a price of zero, an &lt;code&gt;AggregateOffer&lt;/code&gt; where an &lt;code&gt;Offer&lt;/code&gt; is required, one URL serving two currencies, or &lt;code&gt;Product&lt;/code&gt; markup that only exists after JavaScript runs. These are the nine checks, in the order we run them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed on 7 July 2026
&lt;/h2&gt;

&lt;p&gt;Google's documentation changelog records two entries on that date. The first added &lt;code&gt;category&lt;/code&gt; to the merchant listing documentation, detailing how &lt;code&gt;Product.category&lt;/code&gt; can be used with both &lt;code&gt;Text&lt;/code&gt; and &lt;code&gt;CategoryCode&lt;/code&gt; types, aligning with the &lt;code&gt;product_type&lt;/code&gt; and &lt;code&gt;google_product_category&lt;/code&gt; attributes in Merchant Center feeds. The second added a "Sale duration" section to the merchant listing guide.&lt;/p&gt;

&lt;p&gt;Roger Montti, SEJ Staff writer at Search Engine Journal, weighed them this way: "In total, there are three new additions but the biggest change by far is the addition of a new Category property."&lt;/p&gt;

&lt;p&gt;He is right about which one matters more, for a reason that is easy to miss. Category in markup gives Google a page-level statement of what a product is, in Google's own taxonomy, that does not depend on your feed being current. For any seller whose feed lags their catalogue, that is a meaningful new signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 1: Get the required properties right before anything else
&lt;/h2&gt;

&lt;p&gt;Three properties are required on &lt;code&gt;Product&lt;/code&gt; for merchant listing eligibility: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt; and &lt;code&gt;offers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On &lt;code&gt;Offer&lt;/code&gt;, Google requires &lt;code&gt;price&lt;/code&gt; or &lt;code&gt;priceSpecification.price&lt;/code&gt;, &lt;code&gt;priceCurrency&lt;/code&gt; or &lt;code&gt;priceSpecification.priceCurrency&lt;/code&gt;, and &lt;code&gt;priceSpecification&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two rules inside that list break more pages than the rest of this article combined.&lt;/p&gt;

&lt;p&gt;The first is the offer type. Google states it directly: "Product snippets accept an &lt;code&gt;Offer&lt;/code&gt; or &lt;code&gt;AggregateOffer&lt;/code&gt; but merchant listings require an &lt;code&gt;Offer&lt;/code&gt; as the merchant has to be the seller of the product in order to be eligible for merchant listing experiences." Marketplace-style templates that emit &lt;code&gt;AggregateOffer&lt;/code&gt; for a price range are disqualified from merchant listing experiences by construction.&lt;/p&gt;

&lt;p&gt;The second is price. "Unlike product snippets, merchant listing experiences require a price greater than zero." Any page that renders a zero price while stock is being loaded, or for a made-to-order item, is out.&lt;/p&gt;

&lt;p&gt;There is a third rule that quietly decides which of your two prices Google reads: "If you use both the &lt;code&gt;offers.price&lt;/code&gt; and &lt;code&gt;offers.priceSpecification&lt;/code&gt; properties to encode an active price, Google will use the price provided through the &lt;code&gt;offers.price&lt;/code&gt; property and ignore the &lt;code&gt;offers.priceSpecification&lt;/code&gt; property." Templates that were extended over time often end up emitting both, with the stale one at the &lt;code&gt;Offer&lt;/code&gt; level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 2: Understand Google's three price kinds before you touch sale windows
&lt;/h2&gt;

&lt;p&gt;Google's merchant listing documentation defines three kinds of price, and they are distinguished by which properties are absent as much as which are present.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Price kind&lt;/th&gt;
&lt;th&gt;How it is marked&lt;/th&gt;
&lt;th&gt;Disqualifying combination&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Active price&lt;/td&gt;
&lt;td&gt;Neither &lt;code&gt;priceType&lt;/code&gt; nor &lt;code&gt;validForMemberTier&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;None; this is the price Google shows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strikethrough price&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;priceType&lt;/code&gt; set to &lt;code&gt;StrikethroughPrice&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Cannot carry &lt;code&gt;validForMemberTier&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Member price&lt;/td&gt;
&lt;td&gt;Carries &lt;code&gt;validForMemberTier&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Cannot carry &lt;code&gt;priceType&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Google's rule for the overlap is blunt: "Price specifications containing both of these properties are ignored." A member-only sale price marked with both &lt;code&gt;priceType&lt;/code&gt; and &lt;code&gt;validForMemberTier&lt;/code&gt; is not a partially valid price; it is discarded.&lt;/p&gt;

&lt;p&gt;Two related properties are still in beta. &lt;code&gt;membershipPointsEarned&lt;/code&gt; carries the note "This property is in beta, and you may not see an effect in Google Search right away", and &lt;code&gt;validForMemberTier&lt;/code&gt; carries a similar warning that off-page &lt;code&gt;MemberProgramTier&lt;/code&gt; structured data might not show up in Google Search right away. Plan loyalty pricing markup as an investment in feed parity, not as a rich-result win this quarter.&lt;/p&gt;

&lt;p&gt;For a transition period Google also still accepts &lt;code&gt;ListPrice&lt;/code&gt; in place of &lt;code&gt;StrikethroughPrice&lt;/code&gt; for strikethrough prices. New implementations should use &lt;code&gt;StrikethroughPrice&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 3: Put the sale window where Google can read it
&lt;/h2&gt;

&lt;p&gt;This is the new section, and the placement rule is the part teams get wrong.&lt;/p&gt;

&lt;p&gt;Dates go in ISO 8601 format, and Google's own example is &lt;code&gt;2025-12-31T23:59:59+01:00&lt;/code&gt;. Use &lt;code&gt;validFrom&lt;/code&gt; for the start. For the end, use either &lt;code&gt;validThrough&lt;/code&gt; or &lt;code&gt;priceValidUntil&lt;/code&gt;. Google's best practices ask for both a start and an end, for the start to be earlier than or equal to the end, and, in its words: "We recommend including the time and timezone in the [ISO 8601] format for accuracy in Google systems."&lt;/p&gt;

&lt;p&gt;Where those properties go depends on where the sale price lives.&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;Offer&lt;/code&gt; node, when &lt;code&gt;price&lt;/code&gt; on that node holds the current active sale price, add &lt;code&gt;validFrom&lt;/code&gt; and either &lt;code&gt;validThrough&lt;/code&gt; or &lt;code&gt;priceValidUntil&lt;/code&gt; directly to the &lt;code&gt;Offer&lt;/code&gt;:&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;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example kurta set"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"offers"&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;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Offer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.example.in/kurta-set"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1799.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"validFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-20T00:00:00+05:30"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceValidUntil"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-30T23:59:59+05:30"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"priceSpecification"&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;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UnitPriceSpecification"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"priceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org/StrikethroughPrice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2499.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"priceCurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INR"&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="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;On a &lt;code&gt;PriceSpecification&lt;/code&gt; node, when the sale price is defined there rather than on the &lt;code&gt;Offer&lt;/code&gt;, add &lt;code&gt;validFrom&lt;/code&gt; and &lt;code&gt;validThrough&lt;/code&gt; to that node. Google adds a warning worth writing on a sticky note: "Note that the &lt;code&gt;priceValidUntil&lt;/code&gt; property isn't applicable to the &lt;code&gt;PriceSpecification&lt;/code&gt; type."&lt;/p&gt;

&lt;p&gt;That single sentence is the most common new-code bug we expect from this change. A developer reads the property list, sees three date properties, and applies all three uniformly to both node types. &lt;code&gt;priceValidUntil&lt;/code&gt; on a &lt;code&gt;PriceSpecification&lt;/code&gt; is silently meaningless.&lt;/p&gt;

&lt;p&gt;The consequence of getting it wrong is spelled out in the property table: "Your listing may not display if the &lt;code&gt;priceValidUntil&lt;/code&gt; property indicates a past date." A stale sale date does not degrade your listing. It can remove it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 4: Declare category in markup, not only in the feed
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Product.category&lt;/code&gt; accepts &lt;code&gt;Text&lt;/code&gt; or &lt;code&gt;CategoryCode&lt;/code&gt;, and it accepts an array mixing both.&lt;/p&gt;

&lt;p&gt;Plain text works like the &lt;code&gt;product_type&lt;/code&gt; feed attribute and represents your own category label. Google recommends keeping custom product types under the 750-character limit.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CategoryCode&lt;/code&gt; is how you declare a Google Product Category on the page. Set &lt;code&gt;@type&lt;/code&gt; to &lt;code&gt;CategoryCode&lt;/code&gt;, set &lt;code&gt;inCodeSet&lt;/code&gt; to a Google Product Taxonomy URL, and set &lt;code&gt;codeValue&lt;/code&gt; to either the numeric GPC ID or the full category path. Google's own examples use the ID &lt;code&gt;"2271"&lt;/code&gt; and the path &lt;code&gt;"Apparel &amp;amp; Accessories &amp;gt; Clothing &amp;gt; Dresses"&lt;/code&gt;. Paths use &lt;code&gt;&amp;gt;&lt;/code&gt; as the level separator, and each segment in the path must contain at least one letter.&lt;/p&gt;

&lt;p&gt;You can supply several values at once, mixing GPC codes, GPC paths and custom product type strings in one array.&lt;/p&gt;

&lt;p&gt;The engineering judgement here: if your feed and your page disagree about what a product is, the fix is upstream of both. Take the category from the same source of truth that populates your feed, or you have simply created a second place to be wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 5: Give every currency its own URL
&lt;/h2&gt;

&lt;p&gt;Google's technical guidelines say it without qualification: "When offering products for sale in multiple currencies, have a distinct URL per currency. For example, if a product is available for sale in Canadian and US dollars, use two distinct URLs, one per currency."&lt;/p&gt;

&lt;p&gt;Indian D2C brands selling to domestic and NRI or export customers routinely serve INR and USD from the same URL, switching on IP geolocation or a cookie. That pattern is incompatible with merchant listing eligibility, and it is expensive to unwind after a replatform rather than during one.&lt;/p&gt;

&lt;p&gt;The same guideline set adds three more eligibility conditions that catch template-driven sites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Only pages where a shopper can purchase a product are eligible for merchant listing experiences, not pages with links to other sites that sell the product." Affiliate and comparison pages are out.&lt;/li&gt;
&lt;li&gt;"Product rich results only support pages that focus on a single product (or multiple variants of the same product)." Category and collection pages are out, and Google adds that this includes product variants where each variant has a distinct URL.&lt;/li&gt;
&lt;li&gt;"&lt;code&gt;Car&lt;/code&gt; isn't supported automatically as a subtype of Product. For now, include both &lt;code&gt;Car&lt;/code&gt; and &lt;code&gt;Product&lt;/code&gt; types if you want to attach ratings to it and be eligible for the Search feature."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fix 6: Render the markup server-side
&lt;/h2&gt;

&lt;p&gt;Google's guidance on this is a recommendation with a hard operational edge.&lt;/p&gt;

&lt;p&gt;"If you're a merchant optimizing for all types of shopping results, we recommend putting &lt;code&gt;Product&lt;/code&gt; structured data in the initial HTML for best results." Then the reason: "Be aware that dynamically-generated markup can make Shopping crawls less frequent and less reliable, which can be an issue for fast-changing content like product availability and price. If you're using JavaScript to generate &lt;code&gt;Product&lt;/code&gt; markup, make sure your server has enough computing resources to handle increased traffic from Google."&lt;/p&gt;

&lt;p&gt;Read that alongside fix 3. Sale windows, availability and price are exactly the fast-changing fields, and client-rendered markup is exactly where crawl reliability drops. A headless storefront that hydrates its JSON-LD in the browser is combining the two worst options for the fields that matter most during a sale.&lt;/p&gt;

&lt;p&gt;If you are already planning a headless build, this belongs in the architecture decision rather than in a later SEO ticket. We cover the same trade-off from the platform side in our &lt;a href="https://ecorpit.com/ecorpit-seo-safe-replatform-migration-service-india-2026/" rel="noopener noreferrer"&gt;SEO-safe replatform and migration work&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 7: Fix availability and condition enumerations
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;availability&lt;/code&gt; takes an &lt;code&gt;ItemAvailability&lt;/code&gt; value, and Google supports ten: &lt;code&gt;BackOrder&lt;/code&gt;, &lt;code&gt;Discontinued&lt;/code&gt;, &lt;code&gt;InStock&lt;/code&gt;, &lt;code&gt;InStoreOnly&lt;/code&gt;, &lt;code&gt;LimitedAvailability&lt;/code&gt;, &lt;code&gt;OnlineOnly&lt;/code&gt;, &lt;code&gt;OutOfStock&lt;/code&gt;, &lt;code&gt;PreOrder&lt;/code&gt;, &lt;code&gt;PreSale&lt;/code&gt; and &lt;code&gt;SoldOut&lt;/code&gt;. Short names without the URL prefix are also supported.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;itemCondition&lt;/code&gt; takes &lt;code&gt;NewCondition&lt;/code&gt;, &lt;code&gt;RefurbishedCondition&lt;/code&gt; or &lt;code&gt;UsedCondition&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For both, Google says the same thing: "Don't specify more than one value." Systems that map an internal multi-warehouse stock state into schema often emit two availability values for a product that is in stock in one location and back-ordered in another. Pick one, and pick the one a shopper on that URL would experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 8: Move shipping and returns to the organization level
&lt;/h2&gt;

&lt;p&gt;Google's preference here saves work rather than creating it.&lt;/p&gt;

&lt;p&gt;For both &lt;code&gt;shippingDetails&lt;/code&gt; and &lt;code&gt;hasMerchantReturnPolicy&lt;/code&gt;, the documentation says to use the property under &lt;code&gt;Offer&lt;/code&gt; "Only if some of your products have specific shipping policies for which you need to override your global shipping policy, or if you don't provide a standard shipping policy for your business". It adds that "the properties supported for offer-level shipping policies are a subset of the properties supported for organization-level shipping policies", and makes the same point about returns: "Product-level return policies should only be used to override a standard merchant-level return policy or when there is no standard return policy as product-level return policies support only a subset of the properties available for merchant-level return policies."&lt;/p&gt;

&lt;p&gt;So one organization-level policy, referenced by &lt;code&gt;@id&lt;/code&gt;, beats the same block duplicated across 40,000 product pages, and it exposes more properties while it does so.&lt;/p&gt;

&lt;p&gt;While you are in this area, two smaller items. &lt;code&gt;hasCertification&lt;/code&gt; now replaces the older &lt;code&gt;hasEnergyConsumptionDetails&lt;/code&gt; pattern, which Google says it continues to support but no longer recommends. And if you sell anything Google treats as adult-oriented, &lt;code&gt;hasAdultConsideration&lt;/code&gt; is mandatory for those items; Google Search supports only the value &lt;code&gt;https://schema.org/SexualContentConsideration&lt;/code&gt; for that property.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 9: Fix the images, because they are a required property
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;image&lt;/code&gt; is required, and its guidelines are more specific than most teams implement.&lt;/p&gt;

&lt;p&gt;Image URLs must be crawlable and indexable, the images must represent the marked-up content, and the format must be one Google Images supports. Google then recommends "providing multiple high-resolution images (minimum of 50K pixels when multiplying width and height) with the following aspect ratios: 16x9, 4x3, and 1x1."&lt;/p&gt;

&lt;p&gt;A 200 by 200 thumbnail is 40,000 pixels and falls under that recommendation. A single square hero satisfies one of the three suggested aspect ratios. Neither is fatal on its own, and both are cheap to fix during a catalogue image pipeline change.&lt;/p&gt;

&lt;h2&gt;
  
  
  The remediation order we use
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Why it comes first&lt;/th&gt;
&lt;th&gt;Typical fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Offer type and non-zero price&lt;/td&gt;
&lt;td&gt;Hard eligibility gate for merchant listings&lt;/td&gt;
&lt;td&gt;Replace AggregateOffer; suppress zero prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;One currency per URL&lt;/td&gt;
&lt;td&gt;Hard eligibility gate; architectural&lt;/td&gt;
&lt;td&gt;Split routes or subfolders per currency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Markup in initial HTML&lt;/td&gt;
&lt;td&gt;Governs crawl frequency for price and stock&lt;/td&gt;
&lt;td&gt;Move JSON-LD to server render&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Sale duration placement&lt;/td&gt;
&lt;td&gt;New; a past date can remove the listing&lt;/td&gt;
&lt;td&gt;validFrom plus validThrough or priceValidUntil, node-correct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Price-kind collisions&lt;/td&gt;
&lt;td&gt;Whole price specification is ignored&lt;/td&gt;
&lt;td&gt;Never combine priceType and validForMemberTier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Category in markup&lt;/td&gt;
&lt;td&gt;New signal; feed parity&lt;/td&gt;
&lt;td&gt;CategoryCode from the same source as the feed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Availability and condition&lt;/td&gt;
&lt;td&gt;Single-value rule&lt;/td&gt;
&lt;td&gt;Collapse to one value per URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Shipping and returns level&lt;/td&gt;
&lt;td&gt;More properties, less duplication&lt;/td&gt;
&lt;td&gt;Organization-level policy referenced by &lt;a class="mentioned-user" href="https://dev.to/id"&gt;@id&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Images&lt;/td&gt;
&lt;td&gt;Required property, weak defaults&lt;/td&gt;
&lt;td&gt;Multiple resolutions, 16x9, 4x3 and 1x1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Work top down. Rows 1 to 3 decide whether the page can produce a merchant listing at all; the rest decide how good it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;Three things change the calculation for an Indian seller.&lt;/p&gt;

&lt;p&gt;The currency rule bites harder here. Brands selling domestically in rupees and internationally in dollars from one storefront are common, and the single-URL-per-currency requirement forces a routing decision that touches canonical tags, hreflang and the sitemap. Do it during a platform change, not as a patch.&lt;/p&gt;

&lt;p&gt;Feed and page divergence is structural, not accidental. Most Indian D2C brands run a catalogue in one system, a Merchant Center feed generated by a plugin, and a storefront template that emits its own JSON-LD. Three systems, three chances to disagree about price, availability and now category. The new &lt;code&gt;category&lt;/code&gt; property is only worth adding if it reads from the same source as the feed; otherwise it is a third opinion.&lt;/p&gt;

&lt;p&gt;Sale calendars are dense. Festive season sale windows are short, overlapping and heavily discounted, which is exactly the case the new sale duration section is designed for and exactly the case where a stale &lt;code&gt;priceValidUntil&lt;/code&gt; costs a listing during the highest-traffic fortnight of the year.&lt;/p&gt;

&lt;p&gt;Scale explains why this is worth engineering properly rather than patching. The India Brand Equity Foundation, which aggregates figures from press and media reports rather than publishing primary data, puts the industry at Rs 10,82,875 crore (US$ 125 billion) in 2024 heading to Rs 29,88,735 crore (US$ 345 billion) by 2030, with the online shopper base moving from 280 to 300 million in 2025 to a projected 420 to 440 million by 2030. Treat those as directional rather than precise, because IBEF's own page carries competing figures in different sections.&lt;/p&gt;

&lt;p&gt;Teams still moving from the Content API for Shopping will find the feed side of this covered in our note on the &lt;a href="https://ecorpit.com/content-api-shopping-merchant-api-migration-2026/" rel="noopener noreferrer"&gt;Content API to Merchant API migration&lt;/a&gt;, and the same markup discipline that earns rich results is what earns citations in AI answers, which we set out in &lt;a href="https://ecorpit.com/structured-data-json-ld-ai-search-citations-2026/" rel="noopener noreferrer"&gt;structured data and JSON-LD for AI search citations&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we do in a product schema remediation
&lt;/h2&gt;

&lt;p&gt;eCorpIT was founded in 2021 and works from Gurugram. Our commerce engagements here follow a consistent shape.&lt;/p&gt;

&lt;p&gt;We start with a crawl of the live catalogue and extract the JSON-LD each template actually emits, rendered and unrendered, because those two differ on most headless storefronts. We compare that against the Merchant Center feed row by row for price, availability and category, and we produce a defect list ranked by the priority order in the table above rather than by defect count.&lt;/p&gt;

&lt;p&gt;Remediation is then a template change plus a data-source change, not a per-page fix. In most catalogues, four to six templates produce every product page, and the same four defects repeat across tens of thousands of URLs. We fix the template, validate with the Rich Results Test, and watch the merchant listing report in Search Console through a full re-crawl before calling it done.&lt;/p&gt;

&lt;p&gt;Engagements are typically scoped as a fixed-price audit followed by a time-boxed remediation sprint, sized to the number of templates rather than the number of products. Who it is for: Indian D2C brands, marketplaces and B2B commerce teams whose product pages are losing rich results and who need the feed and the page to stop disagreeing.&lt;/p&gt;

&lt;p&gt;We work as senior-led, multi-disciplinary teams, we are assessed at CMMI Level 5, MSME certified and ISO 27001:2022 certified, and we are partners with AWS, Microsoft, Google and Shopify. Where a remediation touches customer data, we design implementations aligned with Digital Personal Data Protection Act requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What did Google change in merchant listing structured data on 7 July 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google added a &lt;code&gt;category&lt;/code&gt; property to &lt;code&gt;Product&lt;/code&gt;, detailing how it works with both &lt;code&gt;Text&lt;/code&gt; and &lt;code&gt;CategoryCode&lt;/code&gt; types to align with the &lt;code&gt;product_type&lt;/code&gt; and &lt;code&gt;google_product_category&lt;/code&gt; feed attributes. It also added a new "Sale duration" section explaining how &lt;code&gt;validFrom&lt;/code&gt;, &lt;code&gt;validThrough&lt;/code&gt; and &lt;code&gt;priceValidUntil&lt;/code&gt; define the effective range for sale prices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where do the sale duration properties go?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;Offer&lt;/code&gt; node, add &lt;code&gt;validFrom&lt;/code&gt; and either &lt;code&gt;validThrough&lt;/code&gt; or &lt;code&gt;priceValidUntil&lt;/code&gt; when the &lt;code&gt;Offer&lt;/code&gt; price holds the active sale price. On a &lt;code&gt;PriceSpecification&lt;/code&gt; node, add &lt;code&gt;validFrom&lt;/code&gt; and &lt;code&gt;validThrough&lt;/code&gt; only. Google states that the &lt;code&gt;priceValidUntil&lt;/code&gt; property is not applicable to the &lt;code&gt;PriceSpecification&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can a past sale date remove my listing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google's documentation says your listing may not display if the &lt;code&gt;priceValidUntil&lt;/code&gt; property indicates a past date. That makes stale sale dates an availability problem rather than a cosmetic one, which matters most during dense festive sale calendars where windows are short and overlapping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is my product page not eligible for merchant listings?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most common hard blocks are using &lt;code&gt;AggregateOffer&lt;/code&gt; where merchant listings require an &lt;code&gt;Offer&lt;/code&gt;, a price that is not greater than zero, a page that links out rather than selling directly, a category or collection page rather than a single product, or one URL serving multiple currencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the new category property replace my Merchant Center feed?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. It gives you a page-level way to express the same information the &lt;code&gt;product_type&lt;/code&gt; and &lt;code&gt;google_product_category&lt;/code&gt; feed attributes carry. It is most useful when it reads from the same source of truth as your feed, so the page and the feed cannot drift apart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should product markup be rendered server-side?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google recommends putting &lt;code&gt;Product&lt;/code&gt; structured data in the initial HTML for best results, and warns that dynamically generated markup can make Shopping crawls less frequent and less reliable. Since price and availability change fastest, client-rendered markup is riskiest for exactly the fields that matter most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many availability values can I use?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One. Google supports ten &lt;code&gt;ItemAvailability&lt;/code&gt; values including &lt;code&gt;InStock&lt;/code&gt;, &lt;code&gt;OutOfStock&lt;/code&gt;, &lt;code&gt;BackOrder&lt;/code&gt;, &lt;code&gt;PreOrder&lt;/code&gt; and &lt;code&gt;SoldOut&lt;/code&gt;, and short names without the URL prefix are accepted, but the documentation says not to specify more than one value. The same single-value rule applies to &lt;code&gt;itemCondition&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should shipping and returns policies sit on the offer or the organization?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Prefer the organization level. Google says to use offer-level shipping and return policies only to override a global policy or when no standard policy exists, and notes that offer-level policies support only a subset of the properties available at the organization level.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT is a Gurugram-based technology consultancy with senior engineering teams working across commerce platforms, product data and search visibility. We audit what your templates actually emit against what your Merchant Center feed sends, rank the defects by the eligibility gates that decide whether a listing can appear at all, and fix them at the template and data-source level rather than page by page. If your product pages have quietly lost rich results and nobody can say which system is wrong, talk to us at &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;/contact-us/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/search/docs/appearance/structured-data/merchant-listing" rel="noopener noreferrer"&gt;Merchant listing (Product, Offer) structured data&lt;/a&gt; - Google Search Central&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/search/updates" rel="noopener noreferrer"&gt;Latest documentation updates&lt;/a&gt; - Google Search Central changelog, 7 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.searchenginejournal.com/googles-new-merchant-listing-structured-data-improves-seo/581879/" rel="noopener noreferrer"&gt;Google's New Merchant Listing Structured Data Improves SEO&lt;/a&gt; - Roger Montti, Search Engine Journal, 9 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://searchengineland.com/google-merchant-listings-support-sale-duration-and-product-category-481730" rel="noopener noreferrer"&gt;Google merchant listings support sale duration and product category&lt;/a&gt; - Search Engine Land, July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ppc.land/google-adds-category-codes-to-merchant-listings-on-july-7/" rel="noopener noreferrer"&gt;Google adds category codes to merchant listings on July 7&lt;/a&gt; - PPC Land, July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.seroundtable.com/google-product-category-sale-duration-merchant-listing-41637.html" rel="noopener noreferrer"&gt;Google Supports Product Category and Sale Duration To Merchant Listing Structured Data&lt;/a&gt; - Search Engine Roundtable, July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.google.com/basepages/producttype/taxonomy-with-ids.en-US.txt" rel="noopener noreferrer"&gt;Google Product Taxonomy with IDs&lt;/a&gt; - Google&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/merchants/answer/6324406" rel="noopener noreferrer"&gt;product_type attribute specification&lt;/a&gt; - Google Merchant Center Help&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/merchants/answer/6324436" rel="noopener noreferrer"&gt;google_product_category attribute specification&lt;/a&gt; - Google Merchant Center Help&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/merchants/answer/6324460" rel="noopener noreferrer"&gt;sale_price_effective_date attribute specification&lt;/a&gt; - Google Merchant Center Help&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/search/docs/appearance/structured-data/product-snippet" rel="noopener noreferrer"&gt;Product snippet (Product, Review, Offer) structured data&lt;/a&gt; - Google Search Central&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/search/docs/appearance/structured-data/product-variants" rel="noopener noreferrer"&gt;Product variant structured data&lt;/a&gt; - Google Search Central&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ibef.org/industry/ecommerce" rel="noopener noreferrer"&gt;E-commerce Industry in India&lt;/a&gt; - India Brand Equity Foundation, last updated June 2026&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last updated: 5 August 2026.&lt;/p&gt;

</description>
      <category>productschema</category>
      <category>merchantlistings</category>
      <category>structureddata</category>
      <category>ecommerceseo</category>
    </item>
    <item>
      <title>Google's 24 July 2026 review rule: a 6-step audit before your stars disappear</title>
      <dc:creator>Manu Shukla</dc:creator>
      <pubDate>Wed, 05 Aug 2026 01:03:47 +0000</pubDate>
      <link>https://dev.to/mr_manushukla/googles-24-july-2026-review-rule-a-6-step-audit-before-your-stars-disappear-i7d</link>
      <guid>https://dev.to/mr_manushukla/googles-24-july-2026-review-rule-a-6-step-audit-before-your-stars-disappear-i7d</guid>
      <description>&lt;h1&gt;
  
  
  Google's 24 July 2026 review rule: a 6-step audit before your stars disappear
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Summary.&lt;/strong&gt; On 24 July 2026 Google added one sentence to its review snippet structured data guidelines: "Don't include fake or undisclosed incentivized reviews on your page or in your structured data markup." The page itself now carries a last-updated stamp of 2026-07-24 UTC. That sentence sits inside the Guidelines section, which opens with a warning that a site violating one or more of these guidelines may receive a manual action. Google gave two examples of what it means: reviews not based on a genuine experience of a product or service, and reviews written in exchange for a benefit such as money, discounts, vouchers or free products where the incentivization is not clearly and prominently disclosed. This is not new law. The US Federal Trade Commission's Rule on the Use of Consumer Reviews and Testimonials has been in effect since 21 October 2024, and its own example of a non-compliant offer is a business saying "Tell us how much you loved your visit to John's Steakhouse and get a $5 coupon". In India the Bureau of Indian Standards published IS 19000:2022 for online consumer reviews and it remains voluntary, while the Central Consumer Protection Authority can fine a manufacturer or endorser up to Rs 10 lakh for a misleading advertisement, rising to Rs 50 lakh for a repeat offence. What changed on 24 July is that a review programme most brands considered a marketing question is now an eligibility question for star ratings in Google Search. This is the audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Google actually wrote, and where it sits
&lt;/h2&gt;

&lt;p&gt;The wording matters, so here it is exactly as published in the technical guidelines for review snippets:&lt;/p&gt;

&lt;p&gt;"Don't include fake or undisclosed incentivized reviews on your page or in your structured data markup. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reviews that aren't based on a genuine experience of a product or service&lt;/li&gt;
&lt;li&gt;Reviews written in exchange for a benefit (such as money, discounts, vouchers, or free products) that don't clearly and prominently disclose the incentivization"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two words in that text do the work. The first is "undisclosed", which means an incentivized review is not automatically disqualifying; an incentivized review without a clear disclosure is. The second is "or", in "on your page or in your structured data markup", which closes the obvious workaround of leaving an undisclosed incentivized review visible on the page while quietly excluding it from the JSON-LD, or the reverse.&lt;/p&gt;

&lt;p&gt;Barry Schwartz, Contributing Editor at Search Engine Land, read the timing the way most practitioners did: "Google added a new guideline to the documentation for a reason; Google probably sees people using these techniques to get fake reviews."&lt;/p&gt;

&lt;p&gt;Placement is the part teams miss. This is not in the spam policies and it is not in a blog post. It is in the Guidelines block of the review snippet reference, directly under a warning that reads: "If your site violates one or more of these guidelines, then Google may take manual action against it. Once you have remedied the problem, you can submit your site for reconsideration." Guidelines in that block govern eligibility for the rich result. The practical exposure is losing stars in search results, and a manual action that has to be cleared through reconsideration.&lt;/p&gt;

&lt;p&gt;Google published no separate announcement alongside the change, which is why plenty of teams running review campaigns still have not seen it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this lands harder in 2026 than it would have in 2023
&lt;/h2&gt;

&lt;p&gt;Two things happened before this guideline that change its weight.&lt;/p&gt;

&lt;p&gt;Google removed the FAQ rich result. A deprecation notice went on the documentation on 8 May 2026, the feature stopped appearing in search from 7 May 2026, and the documentation itself was removed on 15 June 2026. Star ratings are now one of the few remaining visual differentiators an ordinary commercial page can earn in a results layout increasingly dominated by AI Overviews.&lt;/p&gt;

&lt;p&gt;Review data is also flowing into AI answers. Search Engine Land reported on 24 July 2026 that ChatGPT gained access to Yelp reviews, ratings and photos. Rating data is no longer only a snippet decoration; it is an input to systems that summarise a purchase decision on your behalf.&lt;/p&gt;

&lt;p&gt;So the asset getting more valuable is the same asset now governed by a stricter eligibility test. That is the whole reason to spend a day on this audit rather than a quarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Inventory every system that feeds a rating into your markup
&lt;/h2&gt;

&lt;p&gt;Most brands cannot answer this in one sitting, which is the first finding.&lt;/p&gt;

&lt;p&gt;Write down every source that contributes a rating or a review to any page carrying &lt;code&gt;Review&lt;/code&gt; or &lt;code&gt;AggregateRating&lt;/code&gt; markup. In a typical D2C stack that list runs longer than expected: the on-site review widget, post-purchase email review requests, an SMS review flow, a loyalty programme that awards points for reviews, a sampling or seeding programme, an affiliate or creator programme, imported reviews from a marketplace listing, and reviews syndicated from a parent brand or a group site.&lt;/p&gt;

&lt;p&gt;For each source, record four things: does it offer anything in return for the review, does the offer depend in any way on the review being positive, is any disclosure attached to the resulting review, and does the review flow into the structured data.&lt;/p&gt;

&lt;p&gt;Two of Google's older guidelines usually claim their first victims here. "Don't aggregate reviews or ratings from other websites" rules out pulling in marketplace ratings, and "Provide review information about a specific item, not about a category or a list of items" rules out a category page carrying a rating rolled up from its children.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Review source&lt;/th&gt;
&lt;th&gt;Typical Google guideline risk&lt;/th&gt;
&lt;th&gt;What to do first&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Post-purchase email with no incentive&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Confirm reviewer names are valid and under 100 characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Points, coupon or discount for any review&lt;/td&gt;
&lt;td&gt;Undisclosed incentivization if no visible label&lt;/td&gt;
&lt;td&gt;Add an unavoidable disclosure to each affected review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free product seeding or sampling&lt;/td&gt;
&lt;td&gt;Undisclosed incentivization; often no disclosure at all&lt;/td&gt;
&lt;td&gt;Disclose, and check the offer wording for implied sentiment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ratings imported from a marketplace listing&lt;/td&gt;
&lt;td&gt;"Don't aggregate reviews or ratings from other websites"&lt;/td&gt;
&lt;td&gt;Remove from markup; keep on page only if clearly attributed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Embedded third-party widget on your own Organization page&lt;/td&gt;
&lt;td&gt;Self-serving reviews; ineligible for the star feature&lt;/td&gt;
&lt;td&gt;Remove the Organization-level markup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category or collection page rating&lt;/td&gt;
&lt;td&gt;Rating must describe a specific item&lt;/td&gt;
&lt;td&gt;Move markup to the individual product pages&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 2: Classify every review, then count what you lose
&lt;/h2&gt;

&lt;p&gt;Sort each review into one of five buckets: organic, incentivized with an adequate disclosure, incentivized without an adequate disclosure, insider, or fake.&lt;/p&gt;

&lt;p&gt;The fifth bucket is the one to be honest about. Google's first example is "Reviews that aren't based on a genuine experience of a product or service". If a review came from a purchased pack, a review-exchange group, or an agency that could not name the reviewer, it belongs there and it comes out of both the page and the markup.&lt;/p&gt;

&lt;p&gt;Then do the arithmetic before you do the remediation. Take your current &lt;code&gt;ratingValue&lt;/code&gt; and &lt;code&gt;ratingCount&lt;/code&gt;, remove the fake bucket entirely, and recompute. Do the same again excluding the undisclosed incentivized bucket, so you can see the gap between the rating you display today and the rating your genuinely organic reviews support. If those two numbers are far apart, the star rating was never the asset you thought it was, and the drop you are worried about has already been priced into your conversion data as returns and complaints.&lt;/p&gt;

&lt;p&gt;One judgement, stated plainly: a 4.9 built on a seeding programme is a liability with a countdown on it, and the cheapest day to fix it is the day before Google notices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Make the disclosure unavoidable, not merely present
&lt;/h2&gt;

&lt;p&gt;Google's wording is "clearly and prominently disclose". The FTC has published a workable operational definition of a very similar standard, and it is the most useful thing in this whole area.&lt;/p&gt;

&lt;p&gt;Under the FTC rule, a disclosure has to be "clear and conspicuous", and its definition of that term requires the disclosure to be "unavoidable". The FTC explains that a disclosure is avoidable when "a consumer must take any action, such as clicking on a hyperlink or hovering over an icon, to see" it. Asked directly whether a disclosure in the first line of a consumer review is unavoidable, the FTC's answer is that the Commission would consider such a disclosure to be unavoidable.&lt;/p&gt;

&lt;p&gt;That gives you a concrete implementation target. The disclosure belongs in the visible review body, at the start, on the page, in the same text that goes into your markup. Not in a footer. Not in a tooltip. Not in the terms of the loyalty programme.&lt;/p&gt;

&lt;p&gt;Here is what that looks like in the markup, using only properties Google lists as required or recommended for &lt;code&gt;Review&lt;/code&gt;:&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;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example product name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"review"&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;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Review"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reviewRating"&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;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rating"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ratingValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"bestRating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"worstRating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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;"author"&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;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Priya S."&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;"datePublished"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reviewBody"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Received a free sample in exchange for this review. Fit is true to size and the fabric held up after four washes."&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;The disclosure is the first sentence of &lt;code&gt;reviewBody&lt;/code&gt;, so it survives both the on-page render and the markup, and a reader meets it before the opinion. Note also that &lt;code&gt;bestRating&lt;/code&gt; and &lt;code&gt;worstRating&lt;/code&gt; are only recommended: Google assumes 5 and 1 respectively when they are omitted, so include them only when your scale actually differs.&lt;/p&gt;

&lt;p&gt;Watch the author field. Google requires &lt;code&gt;author&lt;/code&gt; for a &lt;code&gt;Review&lt;/code&gt;, states that the reviewer's name must be a valid name, gives "50% off until Saturday" as an example of an invalid one, and specifies that the field must be shorter than 100 characters or the page is not eligible for an author-based review snippet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Recompute the aggregate honestly
&lt;/h2&gt;

&lt;p&gt;A disclosure fixes the individual review. It does not fix the number in the star widget.&lt;/p&gt;

&lt;p&gt;The FTC makes this point about insider reviews and the logic transfers directly to incentivized ones: insider reviews are permitted when the relationship is clearly and conspicuously disclosed, but "if these reviews materially increase the average star rating of a product, the business could be violating the FTC Act even with such disclosures, because consumers might see only the star rating and not look at the individual reviews."&lt;/p&gt;

&lt;p&gt;That is the trap. A page can be fully compliant review by review and still misrepresent itself through the single number most people actually read.&lt;/p&gt;

&lt;p&gt;Practical position: if disclosed incentivized reviews move your average by a material margin, either exclude them from the aggregate you mark up, or show both numbers on the page. Google requires &lt;code&gt;ratingValue&lt;/code&gt; plus at least one of &lt;code&gt;ratingCount&lt;/code&gt; or &lt;code&gt;reviewCount&lt;/code&gt; on &lt;code&gt;AggregateRating&lt;/code&gt;, and it defines &lt;code&gt;reviewCount&lt;/code&gt; as the number of people who provided a review with or without an accompanying rating, so the vocabulary to be precise already exists.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Failure mode&lt;/th&gt;
&lt;th&gt;What the reader sees&lt;/th&gt;
&lt;th&gt;Google exposure&lt;/th&gt;
&lt;th&gt;FTC exposure&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fake reviews in markup&lt;/td&gt;
&lt;td&gt;Inflated stars&lt;/td&gt;
&lt;td&gt;Guideline breach; manual action risk&lt;/td&gt;
&lt;td&gt;Rule violation; civil penalties for knowing violations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incentivized, no disclosure&lt;/td&gt;
&lt;td&gt;Inflated stars&lt;/td&gt;
&lt;td&gt;Guideline breach; manual action risk&lt;/td&gt;
&lt;td&gt;FTC Act exposure for failure to disclose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incentivized for positive sentiment only&lt;/td&gt;
&lt;td&gt;Inflated stars&lt;/td&gt;
&lt;td&gt;Guideline breach&lt;/td&gt;
&lt;td&gt;Section 465.4 violation even with a disclosure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disclosed incentives, aggregate not adjusted&lt;/td&gt;
&lt;td&gt;Inflated average&lt;/td&gt;
&lt;td&gt;Compliant on the letter of the guideline&lt;/td&gt;
&lt;td&gt;Possible FTC Act exposure via the star rating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marketplace ratings imported into markup&lt;/td&gt;
&lt;td&gt;Borrowed credibility&lt;/td&gt;
&lt;td&gt;"Don't aggregate reviews or ratings from other websites"&lt;/td&gt;
&lt;td&gt;Depends on presentation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Organization reviews you control&lt;/td&gt;
&lt;td&gt;Stars on your own brand page&lt;/td&gt;
&lt;td&gt;Ineligible for the star review feature&lt;/td&gt;
&lt;td&gt;Depends on presentation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 5: Clear the self-serving and aggregation traps while you are in there
&lt;/h2&gt;

&lt;p&gt;Two older guidelines cause more lost stars than the new one will, and this audit is the moment to close them.&lt;/p&gt;

&lt;p&gt;The self-serving rule is specific and it is stricter than most teams assume. Google's guideline states that if the entity being reviewed controls the reviews about itself, its pages using &lt;code&gt;LocalBusiness&lt;/code&gt; or any other type of &lt;code&gt;Organization&lt;/code&gt; structured data are ineligible for the star review feature. Google spells out that this covers an embedded third-party widget, naming a Google Business reviews or Facebook reviews widget as examples. A "what our customers say" section on your homepage, marked up at the Organization level, is the single most common instance of this.&lt;/p&gt;

&lt;p&gt;Read the scope carefully before you strip anything. That ineligibility clause is written against &lt;code&gt;LocalBusiness&lt;/code&gt; and &lt;code&gt;Organization&lt;/code&gt; types. Reviews of your own products, marked up on the product page as &lt;code&gt;Product&lt;/code&gt; with nested &lt;code&gt;Review&lt;/code&gt; or &lt;code&gt;AggregateRating&lt;/code&gt;, are a different case and are not covered by that clause. The rule about not aggregating ratings from other websites and the new rule about fake or undisclosed incentivized reviews do apply everywhere.&lt;/p&gt;

&lt;p&gt;For local business ratings Google adds two further requirements: ratings must be sourced directly from users, and you should not rely on human editors to create, curate or compile ratings information for local businesses.&lt;/p&gt;

&lt;p&gt;Also check the visibility requirement, which is easy to fail after a redesign. Google requires that marked-up review content be readily available to users from the marked-up page, and that it be immediately obvious that the page has review content. If your reviews load behind a tab, an accordion or a lazy-loaded widget that never fires for a crawler, the markup is describing content the page does not clearly show.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Validate, then watch the right report
&lt;/h2&gt;

&lt;p&gt;Run the Rich Results Test and the Search Console rich result reports for review snippets. Both catch syntax problems and missing required properties. Neither can tell you whether a review was written in exchange for a free sample, which is why steps 1 to 4 have to be done by a human with access to the marketing calendar.&lt;/p&gt;

&lt;p&gt;Set two monitoring habits. First, watch the review snippet report in Search Console for a drop in valid items, which is what a markup regression looks like. Second, watch the Manual Actions report, which is where a guideline breach surfaces. If a manual action appears, the remedy path is the one named in the documentation: fix the problem, then submit the site for reconsideration.&lt;/p&gt;

&lt;p&gt;Give it time before you conclude anything. Google's own note on the page is that it may take several days after publishing for Google to find and crawl a page, and re-crawling and re-indexing take longer still.&lt;/p&gt;

&lt;p&gt;The same structured-data discipline pays off beyond stars, which is why we treat &lt;a href="https://ecorpit.com/structured-data-json-ld-ai-search-citations-2026/" rel="noopener noreferrer"&gt;structured data and JSON-LD for AI search citations&lt;/a&gt; as part of the same workstream rather than a separate one, and why the wider &lt;a href="https://ecorpit.com/ultimate-guide-seo-2026/" rel="noopener noreferrer"&gt;SEO guide for 2026&lt;/a&gt; puts markup accuracy alongside content quality rather than after it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the FTC rule adds that Google's guideline does not
&lt;/h2&gt;

&lt;p&gt;If you sell into the United States, Google's guideline is the smaller of your two problems.&lt;/p&gt;

&lt;p&gt;The FTC's Rule on the Use of Consumer Reviews and Testimonials took effect on 21 October 2024. On incentives, Section 465.4 draws a line that Google's one-sentence guideline does not: "The rule does not prohibit giving incentives for reviews, as long as there isn't an express or implied requirement that the reviews have to express a particular sentiment. But remember that failing to disclose incentives could be a violation of the FTC Act."&lt;/p&gt;

&lt;p&gt;The sentiment condition is where marketing copy quietly breaks the rule. The FTC's worked example is that you would be implying reviews have to be positive if you wrote "Tell us how much you loved your visit to John's Steakhouse and get a $5 coupon" or "Tell your friends about all the fun you had at Jane's Arcade for a chance to win prizes." Neither sentence contains an explicit condition. Both imply one.&lt;/p&gt;

&lt;p&gt;And a disclosure does not rescue a sentiment-conditioned incentive. Asked whether a business can pay incentives for 5-star reviews on third-party platforms so long as reviewers add a disclosure, the FTC's answer is: "No. That conduct would violate Section 465.4. Note also that this section applies whether the reviews appear on your website or third-party review platforms."&lt;/p&gt;

&lt;p&gt;Three further points are worth knowing before anyone on your team improvises.&lt;/p&gt;

&lt;p&gt;The rule authorises courts to impose civil penalties for knowing violations. The FTC's guidance page states the standard in those terms and does not publish a per-violation figure, so treat any specific number you see quoted as something to verify against the current civil penalty adjustment rather than as settled fact.&lt;/p&gt;

&lt;p&gt;There is no private right of action under the rule, so the enforcement risk is regulatory rather than a class action under this rule specifically.&lt;/p&gt;

&lt;p&gt;Sorting is mostly safe, suppression is not. The FTC says organizing reviews is not suppressing reviews under the rule, and that ordering reviews by rating with five-star reviews on top is not covered by the rule, but adds that organizing reviews in a way that makes it difficult for consumers to find negative reviews could be an unfair or deceptive act under Section 5 of the FTC Act.&lt;/p&gt;

&lt;p&gt;Finally, note that the FTC's guidance is staff guidance and says so directly: it "isn't definitive or comprehensive, and it doesn't provide a safe harbor from potential liability."&lt;/p&gt;

&lt;h2&gt;
  
  
  India-specific considerations
&lt;/h2&gt;

&lt;p&gt;Indian D2C brands and marketplaces sit under a different mix: a voluntary technical standard plus a live enforcement power aimed at advertising.&lt;/p&gt;

&lt;p&gt;The Bureau of Indian Standards published IS 19000:2022, "Online Consumer Reviews: Principles and Requirements for their Collection, Moderation and Publication", covering how review administrators collect, moderate and publish online consumer reviews. It applies to anyone publishing consumer reviews online, including sellers collecting reviews from their own customers, a third party contracted by the seller, and independent third parties. Compliance is voluntary.&lt;/p&gt;

&lt;p&gt;The enforcement teeth are elsewhere. Under the Consumer Protection Act 2019, the Central Consumer Protection Authority can impose a penalty of up to Rs 10 lakh on a manufacturer or endorser for a false or misleading advertisement, with imprisonment of up to two years; for a subsequent offence the fine may extend to Rs 50 lakh and imprisonment to five years. The CCPA can also bar an endorser from endorsing that product or service for up to one year, extending to three years for repeat offences.&lt;/p&gt;

&lt;p&gt;Three practical consequences for an Indian brand.&lt;/p&gt;

&lt;p&gt;A seeding or sampling programme run through creators is advertising as well as review generation, and the endorser-side penalty means your creators carry exposure alongside you. Disclosure protects the creator as well as the brand.&lt;/p&gt;

&lt;p&gt;Marketplace ratings and own-site ratings need to stay separate in your markup. Google's prohibition on aggregating ratings from other websites means your product page cannot borrow the marketplace's star average, however tempting the volume difference.&lt;/p&gt;

&lt;p&gt;If your review programme touches personal data across borders, the review vendor is a processor in your data map like any other. Teams working through that mapping will find the relevant obligations in our &lt;a href="https://ecorpit.com/dpdp-act-engineering-playbook-indian-startups-2026/" rel="noopener noreferrer"&gt;DPDP Act engineering playbook for Indian startups&lt;/a&gt;, and brands selling through open network channels should read it alongside the &lt;a href="https://ecorpit.com/ondc-2026-d2c-brand-seller-scale-playbook/" rel="noopener noreferrer"&gt;ONDC playbook for D2C brands and sellers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit in one page
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pass condition&lt;/th&gt;
&lt;th&gt;Where it is defined&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fake reviews removed&lt;/td&gt;
&lt;td&gt;No review in page or markup lacking a genuine experience&lt;/td&gt;
&lt;td&gt;Google review snippet guidelines, 24 July 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incentives disclosed&lt;/td&gt;
&lt;td&gt;Disclosure visible in the review body, not behind a click&lt;/td&gt;
&lt;td&gt;Google guideline; FTC "unavoidable" standard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No sentiment condition&lt;/td&gt;
&lt;td&gt;Offer wording never implies the review must be positive&lt;/td&gt;
&lt;td&gt;FTC Section 465.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregate not inflated&lt;/td&gt;
&lt;td&gt;Disclosed incentivized reviews do not materially move the average&lt;/td&gt;
&lt;td&gt;FTC Act risk on star ratings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No imported ratings&lt;/td&gt;
&lt;td&gt;No marketplace or third-party ratings inside your markup&lt;/td&gt;
&lt;td&gt;Google: don't aggregate ratings from other websites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No self-serving Organization stars&lt;/td&gt;
&lt;td&gt;No Review or AggregateRating on LocalBusiness or Organization you control&lt;/td&gt;
&lt;td&gt;Google self-serving reviews guideline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviews visible on page&lt;/td&gt;
&lt;td&gt;Review text and rating immediately obvious to a user&lt;/td&gt;
&lt;td&gt;Google technical guidelines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required properties present&lt;/td&gt;
&lt;td&gt;author, itemReviewed or nesting, reviewRating, ratingValue&lt;/td&gt;
&lt;td&gt;Google review snippet reference&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If a row fails, fix the page and the markup together. Fixing only one is how sites end up with markup that no longer matches the page, which is a separate guideline breach.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What exactly did Google change on 24 July 2026?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google added one guideline to its review snippet structured data documentation: do not include fake or undisclosed incentivized reviews on your page or in your structured data markup. It gave two examples, covering reviews not based on genuine experience and reviews written in exchange for a benefit without clear and prominent disclosure of the incentivization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are incentivized reviews now banned outright?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. The guideline targets fake reviews and undisclosed incentivized reviews. An incentivized review with a clear and prominent disclosure is not prohibited by this guideline. Separately, the US FTC rule prohibits conditioning an incentive on the review expressing a particular sentiment, and a disclosure does not cure that specific problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens if my site breaks this guideline?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The guidelines section of Google's review snippet documentation warns that Google may take manual action against a site violating one or more of these guidelines. The practical outcome is losing eligibility for review rich results. After remedying the problem, you can submit the site for reconsideration through Search Console.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where should the disclosure appear?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the visible review text and in the markup, at the start of the review body. The FTC treats a disclosure as avoidable when a consumer must click a hyperlink or hover over an icon to see it, and considers a disclosure in the first line of a consumer review to be unavoidable. Footers and programme terms do not qualify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I still show star ratings on my own homepage?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usually not at the Organization level. Google says that if the reviewed entity controls the reviews about itself, its pages using LocalBusiness or any other Organization structured data are ineligible for the star review feature, including reviews delivered through an embedded third-party widget. Product-level reviews on product pages are a separate case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I import my marketplace ratings into my product pages?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Google's long-standing technical guideline says not to aggregate reviews or ratings from other websites. Your product page markup should describe reviews collected on that page for that specific item. You may still reference a marketplace rating as visible content, provided it is clearly attributed and not marked up as your own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I decide whether to exclude incentivized reviews from my average?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Recompute your rating value and count with and without the incentivized set. If the difference is material, either exclude them from the aggregate you mark up or publish both numbers. The FTC's reasoning is that consumers may see only the star rating and never read the individual reviews or their disclosures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What applies to Indian brands specifically?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Bureau of Indian Standards published IS 19000:2022 on collecting, moderating and publishing online consumer reviews, and compliance is voluntary. Enforcement risk comes from the Consumer Protection Act 2019, under which the Central Consumer Protection Authority can penalise a manufacturer or endorser up to Rs 10 lakh, rising to Rs 50 lakh for repeat offences.&lt;/p&gt;

&lt;h2&gt;
  
  
  How eCorpIT can help
&lt;/h2&gt;

&lt;p&gt;eCorpIT is a Gurugram-based technology consultancy, ISO 27001:2022 certified and assessed at CMMI Level 5, with senior engineering teams working across commerce platforms, structured data and search visibility. We audit review pipelines end to end, from the incentive wording in a post-purchase email through to the JSON-LD a crawler actually receives, and we design implementations aligned with Consumer Protection Act and Digital Personal Data Protection Act requirements. If your stars matter to your conversion rate and you are not certain what is feeding them, talk to us at &lt;a href="https://ecorpit.com/contact-us/" rel="noopener noreferrer"&gt;/contact-us/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/search/docs/appearance/structured-data/review-snippet" rel="noopener noreferrer"&gt;Review snippet (Review, AggregateRating) structured data&lt;/a&gt; - Google Search Central, last updated 24 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/search/updates" rel="noopener noreferrer"&gt;Latest documentation updates&lt;/a&gt; - Google Search Central changelog, July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://searchengineland.com/google-says-dont-include-fake-or-undisclosed-incentivized-reviews-in-review-snippet-structured-data-483456" rel="noopener noreferrer"&gt;Google says don't include fake or undisclosed incentivized reviews in review snippet structured data&lt;/a&gt; - Barry Schwartz, Search Engine Land, 24 July 2026&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ftc.gov/business-guidance/resources/consumer-reviews-testimonials-rule-questions-answers" rel="noopener noreferrer"&gt;The Consumer Reviews and Testimonials Rule: Questions and Answers&lt;/a&gt; - US Federal Trade Commission&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.federalregister.gov/documents/2024/08/22/2024-18519/trade-regulation-rule-on-the-use-of-consumer-reviews-and-testimonials" rel="noopener noreferrer"&gt;Trade Regulation Rule on the Use of Consumer Reviews and Testimonials&lt;/a&gt; - Federal Register, 22 August 2024&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ftc.gov/news-events/news/press-releases/2024/08/federal-trade-commission-announces-final-rule-banning-fake-reviews-testimonials" rel="noopener noreferrer"&gt;Federal Trade Commission Announces Final Rule Banning Fake Reviews and Testimonials&lt;/a&gt; - US Federal Trade Commission, August 2024&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ecfr.gov/current/title-16/chapter-I/subchapter-B/part-255" rel="noopener noreferrer"&gt;FTC Endorsement Guides, 16 CFR Part 255&lt;/a&gt; - Electronic Code of Federal Regulations&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/search/blog/2019/09/making-review-rich-results-more-helpful" rel="noopener noreferrer"&gt;Making review rich results more helpful&lt;/a&gt; - Google Search Central Blog, September 2019&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pib.gov.in/Pressreleaseshare.aspx?PRID=1882828&amp;amp;reg=3&amp;amp;lang=2" rel="noopener noreferrer"&gt;BIS issues standards for organizations publishing consumer reviews&lt;/a&gt; - Press Information Bureau, Government of India&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.medianama.com/2022/12/223-summary-bis-standard-online-reviews-e-commerce/" rel="noopener noreferrer"&gt;Summary: India's new guidelines for reviews on online platforms&lt;/a&gt; - MediaNama, December 2022&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.services.bis.gov.in/php/BIS_2.0/bisconnect/standard_review/Standard_review/Isdetails?ID=Mjc4MTI%3D" rel="noopener noreferrer"&gt;IS 19000:2022 Online Consumer Reviews: Principles and Requirements for their Collection, Moderation and Publication&lt;/a&gt; - Bureau of Indian Standards&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://prsindia.org/billtrack/the-consumer-protection-bill-2019" rel="noopener noreferrer"&gt;The Consumer Protection Bill, 2019&lt;/a&gt; - PRS Legislative Research&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://searchengineland.com/openai-yelp-deal-483326" rel="noopener noreferrer"&gt;ChatGPT gains access to Yelp reviews, ratings, and photos&lt;/a&gt; - Search Engine Land, 24 July 2026&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Last updated: 5 August 2026.&lt;/p&gt;

</description>
      <category>reviewsnippet</category>
      <category>structureddata</category>
      <category>googlesearchcentral</category>
      <category>ftcconsumerreviewrul</category>
    </item>
  </channel>
</rss>
