CINXE.COM
Prompting with images and text using the Gemini API for accessibility | Google for Developers
<!doctype html> <html lang="en" dir="ltr"> <head> <meta name="google-signin-client-id" content="721724668570-nbkv1cfusk7kk4eni4pjvepaus73b13t.apps.googleusercontent.com"> <meta name="google-signin-scope" content="profile email https://www.googleapis.com/auth/developerprofiles https://www.googleapis.com/auth/developerprofiles.award"> <meta property="og:site_name" content="Google for Developers"> <meta property="og:type" content="website"><meta name="robots" content="noindex"><meta name="theme-color" content="#fff"><meta charset="utf-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="/_pwa/developers/manifest.json" crossorigin="use-credentials"> <link rel="preconnect" href="//www.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.googleapis.com" crossorigin> <link rel="preconnect" href="//apis.google.com" crossorigin> <link rel="preconnect" href="//www.google-analytics.com" crossorigin><link rel="stylesheet" href="//fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"> <link rel="stylesheet" href="//fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined&display=block"><link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/css/app.css"> <link rel="shortcut icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/images/favicon-new.png"> <link rel="apple-touch-icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/images/touchicon-180-new.png"><link rel="canonical" href="https://developers.google.com/codelabs/solutions/ai-gemini-images/codelab-1"><link rel="search" type="application/opensearchdescription+xml" title="Google for Developers" href="https://developers.google.com/s/opensearch.xml"> <link rel="alternate" hreflang="en" href="https://developers.google.com/codelabs/solutions/ai-gemini-images/codelab-1" /><link rel="alternate" hreflang="x-default" href="https://developers.google.com/codelabs/solutions/ai-gemini-images/codelab-1" /><title>Prompting with images and text using the Gemini API for accessibility | Google for Developers</title> <meta property="og:title" content="Prompting with images and text using the Gemini API for accessibility | Google for Developers"><meta name="description" content="In this codelab, we will learn how to prompt the Gemini Pro Vision multimodal model using the Gemini API with the NodeJS SDK in JavaScript and explore an accessibility related problem using the API."> <meta property="og:description" content="In this codelab, we will learn how to prompt the Gemini Pro Vision multimodal model using the Gemini API with the NodeJS SDK in JavaScript and explore an accessibility related problem using the API."><meta property="og:url" content="https://developers.google.com/codelabs/solutions/ai-gemini-images/codelab-1"><meta property="og:image" content="https://developers.google.com/static/site-assets/images/home/developers-social-media.png"> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="675"><meta property="og:locale" content="en"><meta name="twitter:card" content="summary"><meta name="twitter:image" content="https://developers.google.com/static/site-assets/images/home/developers-social-media.png"> <link rel="stylesheet" href="/extras.css"></head> <body class="" template="codelab" theme="white" type="codelab" layout="docs" concierge='closed' display-toc pending> <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> <section class="devsite-wrapper"> <devsite-cookie-notification-bar></devsite-cookie-notification-bar><devsite-header role="banner"> <div class="devsite-header--inner nocontent"> <div class="devsite-top-logo-row-wrapper-wrapper"> <div class="devsite-top-logo-row-wrapper"> <div class="devsite-top-logo-row"> <button type="button" id="devsite-hamburger-menu" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Navigation menu button" visually-hidden aria-label="Open menu"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="googleForDevelopers" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/images/lockup-new.svg" class="devsite-site-logo" alt="Google for Developers"> </picture> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item devsite-has-google-wordmark"> </li> </ul> </span> </div> <div class="devsite-top-logo-row-middle"> <div class="devsite-header-upper-tabs"> <devsite-tabs class="upper-tabs"> <nav class="devsite-tabs-wrapper" aria-label="Upper tabs"> <tab class="devsite-dropdown devsite-dropdown-full "> <a href="https://developers.google.com/products" track-metadata-eventdetail="https://developers.google.com/products" class="devsite-tabs-content gc-analytics-event products-dropdown-tab" track-type="nav" track-metadata-position="nav - products" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Products" track-name="products" > Products </a> <a href="#" role="button" aria-haspopup="true" aria-expanded="false" aria-label="Dropdown menu for Products" track-type="nav" track-metadata-eventdetail="https://developers.google.com/products" track-metadata-position="nav - products" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Products" track-name="products" class="devsite-tabs-dropdown-toggle devsite-icon devsite-icon-arrow-drop-down"></a> <div class="devsite-tabs-dropdown" aria-label="submenu" hidden> <div class="devsite-tabs-dropdown-content"> <div class="devsite-tabs-dropdown-column products-dropdown"> <ul class="devsite-tabs-dropdown-section "> <li class="devsite-nav-item"> <a href="https://developers.google.com/products/developer-platforms-and-os?category=DevsiteMarketingPlatformsAndOperatingSystems" class="devsite-products-category" track-type="nav" track-metadata-eventdetail="https://developers.google.com/products/developer-platforms-and-os?category=DevsiteMarketingPlatformsAndOperatingSystems" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> Platforms and Operating Systems </div> </a> </li> <li class="devsite-nav-item"> <a href="//developer.android.com" track-type="nav" track-metadata-eventdetail="//developer.android.com" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="//developer.android.com/static/images/android-logo.svg" srcset=" //developer.android.com/static/images/android-logo.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Android → </div> </a> </li> <li class="devsite-nav-item"> <a href="//ai.google.dev/" track-type="nav" track-metadata-eventdetail="//ai.google.dev/" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/site-assets/logo-google-g.svg" srcset=" /static/site-assets/logo-google-g.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Google AI → </div> </a> </li> <li class="devsite-nav-item"> <a href="//developer.chrome.com" track-type="nav" track-metadata-eventdetail="//developer.chrome.com" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/homepage-assets/images/chromeos-logo.svg" srcset=" /static/homepage-assets/images/chromeos-logo.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Chrome → </div> </a> </li> <li class="devsite-nav-item"> <a href="//cloud.google.com/developers" track-type="nav" track-metadata-eventdetail="//cloud.google.com/developers" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="//gstatic.com/images/branding/product/2x/google_cloud_64dp.png" srcset=" //gstatic.com/images/branding/product/2x/google_cloud_64dp.png" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Google Cloud → </div> </a> </li> <li class="devsite-nav-item"> <a href="//firebase.google.com" track-type="nav" track-metadata-eventdetail="//firebase.google.com" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/_static/firebase/images/icon.svg" srcset=" /_static/firebase/images/icon.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Firebase → </div> </a> </li> </ul> </div> <div class="devsite-tabs-dropdown-column products-dropdown"> <ul class="devsite-tabs-dropdown-section "> <li class="devsite-nav-item"> <a href="https://developers.google.com/products/frameworks-ides-and-sdks?category=DevsiteMarketingIdesFrameworksAndSdks" class="devsite-products-category" track-type="nav" track-metadata-eventdetail="https://developers.google.com/products/frameworks-ides-and-sdks?category=DevsiteMarketingIdesFrameworksAndSdks" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> Frameworks, IDEs, and SDKs </div> </a> </li> <li class="devsite-nav-item"> <a href="//developer.android.com/jetpack" track-type="nav" track-metadata-eventdetail="//developer.android.com/jetpack" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="//developer.android.com/static/images/spot-icons/jetpack-compose.svg" srcset=" //developer.android.com/static/images/spot-icons/jetpack-compose.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Jetpack Compose → </div> </a> </li> <li class="devsite-nav-item"> <a href="//developer.android.com/studio" track-type="nav" track-metadata-eventdetail="//developer.android.com/studio" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="//developer.android.com/static/images/android-logo.svg" srcset=" //developer.android.com/static/images/android-logo.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Android Studio → </div> </a> </li> <li class="devsite-nav-item"> <a href="//flutter.dev" track-type="nav" track-metadata-eventdetail="//flutter.dev" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/site-assets/logo-flutter.svg" srcset=" /static/site-assets/logo-flutter.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Flutter → </div> </a> </li> <li class="devsite-nav-item"> <a href="//idx.dev/" track-type="nav" track-metadata-eventdetail="//idx.dev/" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/products/images/project-idx.png" srcset="https://developers.google.com/static/products/images/project-idx_36.png 36w, https://developers.google.com/static/products/images/project-idx_48.png 48w, https://developers.google.com/static/products/images/project-idx_72.png 72w, https://developers.google.com/static/products/images/project-idx_96.png 96w, https://developers.google.com/static/products/images/project-idx_480.png 480w, https://developers.google.com/static/products/images/project-idx_720.png 720w, https://developers.google.com/static/products/images/project-idx_856.png 856w, https://developers.google.com/static/products/images/project-idx_960.png 960w, https://developers.google.com/static/products/images/project-idx_1440.png 1440w, https://developers.google.com/static/products/images/project-idx_1920.png 1920w, https://developers.google.com/static/products/images/project-idx_2880.png 2880w" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Project IDX → </div> </a> </li> <li class="devsite-nav-item"> <a href="//makersuite.google.com/" track-type="nav" track-metadata-eventdetail="//makersuite.google.com/" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/focus/images/ai-studio-icon.png" srcset="https://developers.google.com/static/focus/images/ai-studio-icon_36.png 36w, https://developers.google.com/static/focus/images/ai-studio-icon_48.png 48w, https://developers.google.com/static/focus/images/ai-studio-icon_72.png 72w, https://developers.google.com/static/focus/images/ai-studio-icon_96.png 96w, https://developers.google.com/static/focus/images/ai-studio-icon_480.png 480w, https://developers.google.com/static/focus/images/ai-studio-icon_720.png 720w, https://developers.google.com/static/focus/images/ai-studio-icon_856.png 856w, https://developers.google.com/static/focus/images/ai-studio-icon_960.png 960w, https://developers.google.com/static/focus/images/ai-studio-icon_1440.png 1440w, https://developers.google.com/static/focus/images/ai-studio-icon_1920.png 1920w, https://developers.google.com/static/focus/images/ai-studio-icon_2880.png 2880w" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Google AI Studio → </div> </a> </li> </ul> </div> <div class="devsite-tabs-dropdown-column products-dropdown"> <ul class="devsite-tabs-dropdown-section "> <li class="devsite-nav-item"> <a href="https://developers.google.com/products/services-and-integrations?category=DevsiteMarketingServicesAndIntegrations" class="devsite-products-category" track-type="nav" track-metadata-eventdetail="https://developers.google.com/products/services-and-integrations?category=DevsiteMarketingServicesAndIntegrations" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> Services and Integrations </div> </a> </li> <li class="devsite-nav-item"> <a href="//ai.google.dev/gemini-api/docs" track-type="nav" track-metadata-eventdetail="//ai.google.dev/gemini-api/docs" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/focus/images/gemini-icon.png" srcset="https://developers.google.com/static/focus/images/gemini-icon_36.png 36w, https://developers.google.com/static/focus/images/gemini-icon_48.png 48w, https://developers.google.com/static/focus/images/gemini-icon_72.png 72w, https://developers.google.com/static/focus/images/gemini-icon_96.png 96w, https://developers.google.com/static/focus/images/gemini-icon_480.png 480w, https://developers.google.com/static/focus/images/gemini-icon_720.png 720w, https://developers.google.com/static/focus/images/gemini-icon_856.png 856w, https://developers.google.com/static/focus/images/gemini-icon_960.png 960w, https://developers.google.com/static/focus/images/gemini-icon_1440.png 1440w, https://developers.google.com/static/focus/images/gemini-icon_1920.png 1920w, https://developers.google.com/static/focus/images/gemini-icon_2880.png 2880w" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Gemini API → </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/privacy-sandbox" track-type="nav" track-metadata-eventdetail="https://developers.google.com/privacy-sandbox" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/privacy-sandbox/assets/images/privacy-sandbox-logo.svg" srcset=" /static/privacy-sandbox/assets/images/privacy-sandbox-logo.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Privacy Sandbox → </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/identity" track-type="nav" track-metadata-eventdetail="https://developers.google.com/identity" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/site-assets/logo-google-g.svg" srcset=" /static/site-assets/logo-google-g.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Identity </div> </a> </li> <li class="devsite-nav-item"> <a href="//checks.google.com/" track-type="nav" track-metadata-eventdetail="//checks.google.com/" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/checks/images/Checks_Icon.png" srcset="https://developers.google.com/static/checks/images/Checks_Icon_36.png 36w, https://developers.google.com/static/checks/images/Checks_Icon_48.png 48w, https://developers.google.com/static/checks/images/Checks_Icon_72.png 72w, https://developers.google.com/static/checks/images/Checks_Icon_96.png 96w, https://developers.google.com/static/checks/images/Checks_Icon_480.png 480w, https://developers.google.com/static/checks/images/Checks_Icon_720.png 720w, https://developers.google.com/static/checks/images/Checks_Icon_856.png 856w, https://developers.google.com/static/checks/images/Checks_Icon_960.png 960w, https://developers.google.com/static/checks/images/Checks_Icon_1440.png 1440w, https://developers.google.com/static/checks/images/Checks_Icon_1920.png 1920w, https://developers.google.com/static/checks/images/Checks_Icon_2880.png 2880w" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Checks → </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/workspace" track-type="nav" track-metadata-eventdetail="https://developers.google.com/workspace" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/site-assets/logo-google-g.svg" srcset=" /static/site-assets/logo-google-g.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Google Workspace </div> </a> </li> </ul> </div> <div class="devsite-tabs-dropdown-column products-dropdown"> <ul class="devsite-tabs-dropdown-section "> <li class="devsite-nav-item"> <a href="https://developers.google.com/products/growth-and-monetization?category=DevsiteMarketingGrowthAndMonetization" class="devsite-products-category" track-type="nav" track-metadata-eventdetail="https://developers.google.com/products/growth-and-monetization?category=DevsiteMarketingGrowthAndMonetization" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> Growth and Monetization </div> </a> </li> <li class="devsite-nav-item"> <a href="//developer.android.com/distribute/" track-type="nav" track-metadata-eventdetail="//developer.android.com/distribute/" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="//gstatic.com/images/branding/product/2x/play_prism_64dp.png" srcset=" //gstatic.com/images/branding/product/2x/play_prism_64dp.png" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Google Play → </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/admob" track-type="nav" track-metadata-eventdetail="https://developers.google.com/admob" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="//gstatic.com/images/branding/product/2x/admob_36dp.png" srcset=" //gstatic.com/images/branding/product/2x/admob_36dp.png" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Google AdMob </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/google-ads" track-type="nav" track-metadata-eventdetail="https://developers.google.com/google-ads" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/homepage-assets/images/google-ads.svg" srcset=" /static/homepage-assets/images/google-ads.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Google Ads </div> </a> </li> <li class="devsite-nav-item"> <a href="//developer.chrome.com/docs/extensions" track-type="nav" track-metadata-eventdetail="//developer.chrome.com/docs/extensions" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/homepage-assets/images/chromeos-logo.svg" srcset=" /static/homepage-assets/images/chromeos-logo.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Chrome Extensions → </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/search" track-type="nav" track-metadata-eventdetail="https://developers.google.com/search" track-metadata-position="nav - products" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-icon-container" size="medium" > <picture> <img class="devsite-nav-item-icon" alt="" src="https://developers.google.com/static/search/images/google-search-central-logo.svg" srcset=" /static/search/images/google-search-central-logo.svg" sizes="100vw" loading="lazy" > </picture> </div> <div class="devsite-nav-item-title"> Google Search Central </div> </a> </li> </ul> </div> </div> </div> </tab> <tab > <a href="https://developers.google.com/solutions/catalog" track-metadata-eventdetail="https://developers.google.com/solutions/catalog" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - solutions" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Solutions" track-name="solutions" > Solutions </a> </tab> <tab > <a href="https://developers.google.com/events" track-metadata-eventdetail="https://developers.google.com/events" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - events" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Events" track-name="events" > Events </a> </tab> <tab > <a href="https://developers.google.com/learn" track-metadata-eventdetail="https://developers.google.com/learn" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - learn" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Learn" track-name="learn" aria-label="Learning Catalog" > Learn </a> </tab> <tab class="devsite-dropdown "> <a href="https://developers.google.com/community" track-metadata-eventdetail="https://developers.google.com/community" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - community" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Community" track-name="community" > Community </a> <a href="#" role="button" aria-haspopup="true" aria-expanded="false" aria-label="Dropdown menu for Community" track-type="nav" track-metadata-eventdetail="https://developers.google.com/community" track-metadata-position="nav - community" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Community" track-name="community" class="devsite-tabs-dropdown-toggle devsite-icon devsite-icon-arrow-drop-down"></a> <div class="devsite-tabs-dropdown" aria-label="submenu" hidden> <div class="devsite-tabs-dropdown-content"> <div class="devsite-tabs-dropdown-column "> <ul class="devsite-tabs-dropdown-section "> <li class="devsite-nav-title" role="heading" tooltip>Communities</li> <li class="devsite-nav-item"> <a href="https://developers.google.com/community/gdg" track-type="nav" track-metadata-eventdetail="https://developers.google.com/community/gdg" track-metadata-position="nav - community" track-metadata-module="tertiary nav" track-metadata-module_headline="communities" tooltip > <div class="devsite-nav-item-title"> Google Developer Groups </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/community/gdsc" track-type="nav" track-metadata-eventdetail="https://developers.google.com/community/gdsc" track-metadata-position="nav - community" track-metadata-module="tertiary nav" track-metadata-module_headline="communities" tooltip > <div class="devsite-nav-item-title"> Google Developer Student Clubs </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/womentechmakers" track-type="nav" track-metadata-eventdetail="https://developers.google.com/womentechmakers" track-metadata-position="nav - community" track-metadata-module="tertiary nav" track-metadata-module_headline="communities" tooltip > <div class="devsite-nav-item-title"> Women Techmakers </div> </a> </li> </ul> </div> <div class="devsite-tabs-dropdown-column "> <ul class="devsite-tabs-dropdown-section "> <li class="devsite-nav-title" role="heading" tooltip>Programs</li> <li class="devsite-nav-item"> <a href="https://developers.google.com/community/accelerators" track-type="nav" track-metadata-eventdetail="https://developers.google.com/community/accelerators" track-metadata-position="nav - community" track-metadata-module="tertiary nav" track-metadata-module_headline="programs" tooltip > <div class="devsite-nav-item-title"> Accelerator </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/community/experts" track-type="nav" track-metadata-eventdetail="https://developers.google.com/community/experts" track-metadata-position="nav - community" track-metadata-module="tertiary nav" track-metadata-module_headline="programs" tooltip > <div class="devsite-nav-item-title"> Google Developer Experts </div> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.google.com/community/tec" track-type="nav" track-metadata-eventdetail="https://developers.google.com/community/tec" track-metadata-position="nav - community" track-metadata-module="tertiary nav" track-metadata-module_headline="programs" tooltip > <div class="devsite-nav-item-title"> Tech Equity Collective </div> </a> </li> </ul> </div> </div> </div> </tab> <tab > <a href="https://developers.google.com/profile/u/me/dashboard" track-metadata-eventdetail="https://developers.google.com/profile/u/me/dashboard" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - developer program" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Developer Program" track-name="developer program" > Developer Program </a> </tab> <tab > <a href="https://developers.googleblog.com" track-metadata-eventdetail="https://developers.googleblog.com" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - blog" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Blog" track-name="blog" > Blog </a> </tab> </nav> </devsite-tabs> </div> <devsite-search enable-signin enable-search enable-suggestions enable-query-completion project-name="Google for Developers" tenant-name="Google for Developers" > <form class="devsite-search-form" action="https://developers.google.com/s/results" method="GET"> <div class="devsite-search-container"> <button type="button" search-open class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Open search"></button> <div class="devsite-searchbox"> <input aria-activedescendant="" aria-autocomplete="list" aria-label="Search" aria-expanded="false" aria-haspopup="listbox" autocomplete="off" class="devsite-search-field devsite-search-query" name="q" placeholder="Search" role="combobox" type="text" value="" > <div class="devsite-search-image material-icons" aria-hidden="true"> </div> <div class="devsite-search-shortcut-icon-container" aria-hidden="true"> <kbd class="devsite-search-shortcut-icon">/</kbd> </div> </div> </div> </form> <button type="button" search-close class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Close search"></button> </devsite-search> </div> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> <devsite-user enable-profiles fp-auth id="devsite-user"> <span class="button devsite-top-button" aria-hidden="true" visually-hidden>Sign in</span> </devsite-user> </div> </div> </div> <div class="devsite-collapsible-section devsite-header-no-lower-tabs "> <div class="devsite-header-background"> </div> </div> </div> </devsite-header> <devsite-book-nav scrollbars hidden> <div class="devsite-book-nav-filter" hidden> <span class="filter-list-icon material-icons" aria-hidden="true"></span> <input type="text" placeholder="Filter" aria-label="Type to filter" role="searchbox"> <span class="filter-clear-button hidden" data-title="Clear filter" aria-label="Clear filter" role="button" tabindex="0"></span> </div> <nav class="devsite-book-nav devsite-nav nocontent" aria-label="Side menu"> <div class="devsite-mobile-header"> <button type="button" id="devsite-close-nav" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Close navigation" aria-label="Close navigation"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="googleForDevelopers" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/images/lockup-new.svg" class="devsite-site-logo" alt="Google for Developers"> </picture> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item devsite-has-google-wordmark"> </li> </ul> </span> </div> </div> <div class="devsite-book-nav-wrapper"> <div class="devsite-mobile-nav-top"> <ul class="devsite-nav-list"> <li class="devsite-nav-item"> <a href="/products" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Products" track-name="products" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Products" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Products </span> </a> <ul class="devsite-nav-responsive-tabs devsite-nav-has-menu "> <li class="devsite-nav-item"> <span class="devsite-nav-title" tooltip data-category="Site-Wide Custom Events" data-label="Tab: Products" track-name="products" > <span class="devsite-nav-text" tooltip menu="Products"> More </span> <span class="devsite-nav-icon material-icons" data-icon="forward" menu="Products"> </span> </span> </li> </ul> </li> <li class="devsite-nav-item"> <a href="/solutions/catalog" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Solutions" track-name="solutions" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Solutions" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Solutions </span> </a> </li> <li class="devsite-nav-item"> <a href="/events" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Events" track-name="events" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Events" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Events </span> </a> </li> <li class="devsite-nav-item"> <a href="/learn" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Learn" track-name="learn" aria-label="Learning Catalog" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Learn" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Learn </span> </a> </li> <li class="devsite-nav-item"> <a href="/community" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Community" track-name="community" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Community" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Community </span> </a> <ul class="devsite-nav-responsive-tabs devsite-nav-has-menu "> <li class="devsite-nav-item"> <span class="devsite-nav-title" tooltip data-category="Site-Wide Custom Events" data-label="Tab: Community" track-name="community" > <span class="devsite-nav-text" tooltip menu="Community"> More </span> <span class="devsite-nav-icon material-icons" data-icon="forward" menu="Community"> </span> </span> </li> </ul> </li> <li class="devsite-nav-item"> <a href="/profile/u/me/dashboard" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Developer Program" track-name="developer program" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Developer Program" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Developer Program </span> </a> </li> <li class="devsite-nav-item"> <a href="https://developers.googleblog.com" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Blog" track-name="blog" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Blog" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Blog </span> </a> </li> </ul> </div> <div class="devsite-mobile-nav-bottom"> <ul class="devsite-nav-list" menu="Products" aria-label="Side menu" hidden> <li class="devsite-nav-item"> <a href="/products/developer-platforms-and-os?category=DevsiteMarketingPlatformsAndOperatingSystems" class="devsite-products-category" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Platforms and Operating Systems" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Platforms and Operating Systems </span> </a> </li> <li class="devsite-nav-item"> <a href="//developer.android.com" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Android →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Android → </span> </a> </li> <li class="devsite-nav-item"> <a href="//ai.google.dev/" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google AI →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google AI → </span> </a> </li> <li class="devsite-nav-item"> <a href="//developer.chrome.com" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Chrome →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Chrome → </span> </a> </li> <li class="devsite-nav-item"> <a href="//cloud.google.com/developers" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Cloud →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google Cloud → </span> </a> </li> <li class="devsite-nav-item"> <a href="//firebase.google.com" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Firebase →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Firebase → </span> </a> </li> <li class="devsite-nav-item"> <a href="/products/frameworks-ides-and-sdks?category=DevsiteMarketingIdesFrameworksAndSdks" class="devsite-products-category" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Frameworks, IDEs, and SDKs" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Frameworks, IDEs, and SDKs </span> </a> </li> <li class="devsite-nav-item"> <a href="//developer.android.com/jetpack" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Jetpack Compose →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Jetpack Compose → </span> </a> </li> <li class="devsite-nav-item"> <a href="//developer.android.com/studio" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Android Studio →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Android Studio → </span> </a> </li> <li class="devsite-nav-item"> <a href="//flutter.dev" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Flutter →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Flutter → </span> </a> </li> <li class="devsite-nav-item"> <a href="//idx.dev/" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Project IDX →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Project IDX → </span> </a> </li> <li class="devsite-nav-item"> <a href="//makersuite.google.com/" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google AI Studio →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google AI Studio → </span> </a> </li> <li class="devsite-nav-item"> <a href="/products/services-and-integrations?category=DevsiteMarketingServicesAndIntegrations" class="devsite-products-category" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Services and Integrations" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Services and Integrations </span> </a> </li> <li class="devsite-nav-item"> <a href="//ai.google.dev/gemini-api/docs" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Gemini API →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Gemini API → </span> </a> </li> <li class="devsite-nav-item"> <a href="/privacy-sandbox" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Privacy Sandbox →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Privacy Sandbox → </span> </a> </li> <li class="devsite-nav-item"> <a href="/identity" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Identity" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Identity </span> </a> </li> <li class="devsite-nav-item"> <a href="//checks.google.com/" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Checks →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Checks → </span> </a> </li> <li class="devsite-nav-item"> <a href="/workspace" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Workspace" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google Workspace </span> </a> </li> <li class="devsite-nav-item"> <a href="/products/growth-and-monetization?category=DevsiteMarketingGrowthAndMonetization" class="devsite-products-category" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Growth and Monetization" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Growth and Monetization </span> </a> </li> <li class="devsite-nav-item"> <a href="//developer.android.com/distribute/" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Play →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google Play → </span> </a> </li> <li class="devsite-nav-item"> <a href="/admob" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google AdMob" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google AdMob </span> </a> </li> <li class="devsite-nav-item"> <a href="/google-ads" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Ads" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google Ads </span> </a> </li> <li class="devsite-nav-item"> <a href="//developer.chrome.com/docs/extensions" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Chrome Extensions →" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Chrome Extensions → </span> </a> </li> <li class="devsite-nav-item"> <a href="/search" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Search Central" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google Search Central </span> </a> </li> </ul> <ul class="devsite-nav-list" menu="Community" aria-label="Side menu" hidden> <li class="devsite-nav-item devsite-nav-heading"> <span class="devsite-nav-title" tooltip > <span class="devsite-nav-text" tooltip > Communities </span> </span> </li> <li class="devsite-nav-item"> <a href="/community/gdg" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Developer Groups" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google Developer Groups </span> </a> </li> <li class="devsite-nav-item"> <a href="/community/gdsc" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Developer Student Clubs" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google Developer Student Clubs </span> </a> </li> <li class="devsite-nav-item"> <a href="/womentechmakers" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Women Techmakers" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Women Techmakers </span> </a> </li> <li class="devsite-nav-item devsite-nav-heading"> <span class="devsite-nav-title" tooltip > <span class="devsite-nav-text" tooltip > Programs </span> </span> </li> <li class="devsite-nav-item"> <a href="/community/accelerators" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Accelerator" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Accelerator </span> </a> </li> <li class="devsite-nav-item"> <a href="/community/experts" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Google Developer Experts" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Google Developer Experts </span> </a> </li> <li class="devsite-nav-item"> <a href="/community/tec" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Tech Equity Collective" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Tech Equity Collective </span> </a> </li> </ul> </div> </div> </nav> </devsite-book-nav> <section id="gc-wrapper"> <main role="main" class="devsite-main-content" > <devsite-content> <article class="devsite-article"><style> body { transition: opacity ease-in 0.2s; } body[unresolved] { opacity: 0; display: block; overflow: hidden; position: relative; } </style> <div class="devsite-banner devsite-banner-announcement nocontent" > <div class="devsite-banner-message"> <div class="devsite-banner-message-text"> <style> .devsite-banner-announcement { background: #1a73e8; color: white; font-size: 16px; font-weight: 500; } .devsite-banner-announcement a { color: white !important; font-weight: 700; } .devsite-banner-announcement a:link:not(.button), .devsite-banner-announcement a:visited:not(.button) { background: 0; } .devsite-banner-announcement a:hover, .devsite-banner-announcement a:focus { text-decoration: none; } .devsite-banner-announcement .devsite-banner-message-text { margin: 0 auto; } </style> <span class="nocontent">Build with Gemini, our largest and most capable AI model. <a href="https://aistudio.google.com/app/prompts/new_chat/?utm_source=gfd&utm_medium=referral&utm_campaign=top_bar&utm_content=" class="gc-analytics-event nocontent" data-category="Announcement" data-label="Gemini promotion">Get an API key.</a> </span> </div> </div> </div> <div class="devsite-article-meta nocontent" role="navigation"> <ul class="devsite-breadcrumb-list" aria-label="Breadcrumb"> <li class="devsite-breadcrumb-item "> <a href="https://developers.google.com/" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="1" track-type="globalNav" track-name="breadcrumb" track-metadata-position="1" track-metadata-eventdetail="Google for Developers" > Google for Developers </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://developers.google.com/products" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="2" track-type="globalNav" track-name="breadcrumb" track-metadata-position="2" track-metadata-eventdetail="" > Products </a> </li> </ul> </div> <h1 class="devsite-page-title" tabindex="-1"> Prompting with images and text using the Gemini API for accessibility </h1> <devsite-feature-tooltip ack-key="AckCollectionsBookmarkTooltipDismiss" analytics-category="Site-Wide Custom Events" analytics-action-show="Callout Profile displayed" analytics-action-close="Callout Profile dismissed" analytics-label="Create Collection Callout" class="devsite-page-bookmark-tooltip nocontent" dismiss-button="true" id="devsite-collections-dropdown" dismiss-button-text="Dismiss" close-button-text="Got it"> <devsite-bookmark></devsite-bookmark> <span slot="popout-heading"> Stay organized with collections </span> <span slot="popout-contents"> Save and categorize content based on your preferences. </span> </devsite-feature-tooltip> <devsite-toc class="devsite-nav" depth="1" devsite-toc-embedded > </devsite-toc> <div class="devsite-article-body clearfix "> <google-codelab-analytics gaid="UA-49880327-14" ga4id="G-JTFZSJVVVZ"></google-codelab-analytics> <google-codelab codelab-gaid="" codelab-ga4id="" doc-id="1kpvc2fhCkzNEpw0U1im6zBqOE90VeeJq0BZFrAHuLG4" id="codelabs/solutions/ai-gemini-images/codelab-1" title="Prompting with images and text using the Gemini API for accessibility" no-tooltip="" environment="web" category="" feedback-link="" layout="scrolling" > <google-codelab-step label="Introduction" duration="1" step="0"> <google-codelab-about codelab-title="Prompting with images and text using the Gemini API for accessibility" authors="Tom Greenaway" last-updated="2024-09-18T19:33:22Z" duration="40"> </google-codelab-about> <h2 class="step-title" id="0" data-text="Introduction" tabindex="-1"> 1. Introduction </h2> <p>Gemini is a multimodal model capable of receiving multiple input data types such as text, image and audio and returning multiple output types of the same variety.</p> <p>In this codelab, you will learn how to access the Google Generative AI API to access the Gemini Pro Vision model and send multimodal payloads of text and image data to the Gemini API and receive a text-only response.</p> <p>You will achieve this by first calling the API with a text-only response and then attaching image payloads. Through this process you will explore a variety of types of prompts that can be used with images and learn how to effectively "think" about prompting with image payloads in mind.</p> <p>Let's get started.</p> <h2 is-upgraded id="prerequisites" data-text="Prerequisites" tabindex="-1"><strong>Prerequisites</strong></h2> <ul> <li>A basic understanding of JavaScript.</li> <li>Command-line access to a computer with NodeJS and NPM installed.</li> </ul> <h2 class="checklist" is-upgraded id="what-youll-learn" data-text="What you'll learn" tabindex="-1"><strong>What you'll learn</strong></h2> <ul class="checklist"> <li>How to access the Gemini API.</li> <li>How to send text and receive text from the Gemini API.</li> <li>How to send text and images to the API.</li> </ul> </google-codelab-step> <google-codelab-step label="Accessing the Gemini API" duration="5" step="1"> <h2 class="step-title" id="1" data-text="Accessing the Gemini API" tabindex="-1"> 2. Accessing the Gemini API </h2> <p>We'll begin by installing the Google Generative AI SDK via the pip command:</p> <pre translate="no" dir="ltr">npm install @google-ai/generativelanguage </pre> <p>Next let's create a basic NodeJS script to execute our API calls.</p> <p>Create a file called script.js and the following import statements to access the library:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">const { GoogleGenerativeAI } = require("@google/generative-ai"); const generationConfig = { temperature: 0.7, candidateCount: 1, topK: 40, topP: 0.95, maxOutputTokens: 1024, }; const safetySettings = [ { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_NONE' }, ]; const genAI = new GoogleGenerativeAI(process.env.API_KEY); const model = genAI.getGenerativeModel({ model: "gemini-pro", }); model.generateContent({ generationConfig, safetySettings, contents: [ { role: "user", parts: [ { text: 'On what planet do humans live? ' } }, ], }).then(result => { console.log(JSON.stringify(result, null, 2)); }); </code></pre> <p>After saving the file, try executing the following command to test the API:</p> <pre translate="no" dir="ltr">node script.js </pre> <p>If you have the environment variable set for your API key then the script should execute successfully. If not, you can set the API key via the following command:</p> <pre translate="no" dir="ltr">export API_KEY=<YOUR API KEY GOES HERE> </pre> <p>When executing successfully, the result should look something like:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">{ "response": { "candidates": [ { "content": { "parts": [ { "text": "Humans currently only live on one planet: Earth. There are no known human colonies or permanent settlements on any other planets in our solar system or beyond." } ], "role": "model" }, "finishReason": "STOP", "index": 0, "safetyRatings": [ { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "probability": "NEGLIGIBLE" }, { "category": "HARM_CATEGORY_HATE_SPEECH", "probability": "NEGLIGIBLE" }, { "category": "HARM_CATEGORY_HARASSMENT", "probability": "NEGLIGIBLE" }, { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "probability": "NEGLIGIBLE" } ] } ], "promptFeedback": { "safetyRatings": [ { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "probability": "NEGLIGIBLE" }, { "category": "HARM_CATEGORY_HATE_SPEECH", "probability": "NEGLIGIBLE" }, { "category": "HARM_CATEGORY_HARASSMENT", "probability": "NEGLIGIBLE" }, { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "probability": "NEGLIGIBLE" } ] } } } </code></pre> <p>We successfully accessed the API. But we only prompted with text to the model and we received a text response. This is for two reasons, we're only using the Gemini Pro model but if we want to attach images to our prompt payload we need to access the Gemini Pro Vision model via the API. Secondly, we are not supplying an image payload.</p> <p>Let's try accessing the Gemini Pro Vision model and see what happens.</p> <p>Update the model on like so:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">const model = genAI.getGenerativeModel({ model: "gemini-pro-vision", }); </code></pre> <p>And in the text prompt, try changing it to this:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">contents: [ { role: "user", parts: [ { text: 'Can you see an image attached to this message?' }, ] } ] </code></pre> <p>If you re-run the script via the commandline:</p> <pre translate="no" dir="ltr">node script.js </pre> <p>You should receive an error:</p> <pre translate="no" dir="ltr">node:internal/process/promises:288 triggerUncaughtException(err, true /* fromPromise */); ^ Error: [400 Bad Request] Add an image to use models/gemini-pro-vision, or switch your model to a text model. </pre> <p>What happened? Now that we've swapped to the Gemini Pro Vision model, the API expects an image to be attached with the API call. However, we only sent text. Hence the error.</p> <p>In the next step, we'll attach an image and ask the LLM questions about the image. To do this, we'll need to load the image into JavaScript and encode it into Base64 encoding.</p> </google-codelab-step> <google-codelab-step label="Seeing is believing" duration="3" step="2"> <h2 class="step-title" id="2" data-text="Seeing is believing" tabindex="-1"> 3. Seeing is believing </h2> <p>First we'll need to access a local image. I recommend finding a picture of a cat and using it. Here's a photo I took:</p> <p class="image-container"><img alt="cd292507e95bdbf6.png" style="width: 543.50px" src="/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6.png" srcset="https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_36.png 36w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_48.png 48w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_72.png 72w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_96.png 96w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_480.png 480w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_720.png 720w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_856.png 856w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_960.png 960w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_1440.png 1440w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_1920.png 1920w,https://developers.google.com/static/codelabs/solutions/ai-gemini-images/codelab-1/img/cd292507e95bdbf6_2880.png 2880w" sizes="(max-width: 840px) 100vw, 856px"></p> <p>First we'll need the join function from the ‘path' package in NodeJS. Let's add this to the top of the script:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">const { join } = require('path'); </code></pre> <p>And before we engage with the Gemini API, add this code as well:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">const base64Image = Buffer.from(fs.readFileSync(join(__dirname, src))).toString("base64"); </code></pre> <p>Assuming that we've placed the cat.png picture next to the <a href="http://script.js" target="_blank">script.js</a> file in our file system.</p> <p>The above code means that we've loaded the picture into memory as a Base 64 encoded variable titled base64Image. We can now include this in the prompt, like so:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr"> contents: [ { role: "user", parts: [ { text: 'Can you see an image attached to this message?' }, { inlineData: { mimeType: 'image/png', data: base64Image } }, ] }, ], </code></pre> <p>If we re-run the script on the command line, the output should look something like this:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">{ "response": { "candidates": [ { "content": { "parts": [ { "text": " Yes, I can see a cat sleeping in the grass." } ], "role": "model" }, ... </code></pre> <p>Success! The Gemini Pro Vision model saw the attached photo of the cat and described it.</p> </google-codelab-step> <google-codelab-step label="Making pictures more accessible" duration="10" step="3"> <h2 class="step-title" id="3" data-text="Making pictures more accessible" tabindex="-1"> 4. Making pictures more accessible </h2> <p>Now that our script is communicating successfully with the Gemini API and we're able to send images and text as prompts. Let's try leveraging this new capability in a way to help users. We're going to adapt our script to read a local HTML file, parse the file for <IMG> tags and add ‘alt' text attributes for any images that are missing tags.</p> <p>We'll start by creating a simple HTML page. Let's name it input.html:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr"><html> <body> <img src="cat.png" /> <img src="cat.png" alt="It's a cat." /> <img src="cat.png" alt="It's a dog." /> </body> </html> </code></pre> <p>We'll need to pull in some additional packages to make this work simpler. Include ‘cheerio' and ‘fs' near the top of your script:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">const cheerio = require("cheerio"); const fs = require("fs"); </code></pre> <p>Next, we'll reorganize our script to execute a ‘main' function and read the input.html file before parsing it using Cheerio. Cheerio gives us a simple query selector function for the file, similar to old school jQuery syntax.</p> <p>We can then query the HTML file using $("img") and loop through the images in the file:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">async function main() { const html = fs.readFileSync("input.html", "utf8"); const $ = cheerio.load(html); $("img").each(function (i, element) { const src = $(element).attr("src"); const originalAlt = $(element).attr("alt"); if (!fs.existsSync(src)) { console.log("Image doesn't exist", src); return; } const base64Image = Buffer.from(fs.readFileSync(join(__dirname, src))).toString("base64"); if (originalAlt !== undefined) { console.log("Alt text is already defined:", originalAlt); return; } // TODO: Query Gemini API with the image and ask for a description // to update the missing alt text } main(); </code></pre> <p>For each image, we check if the image exists locally and we encode it to Base 64 if it does. On top of that, we check if the image tag already has an ‘alt' text attribute. If it does, we skip the image.</p> <p>Finally, we need to fill in the logic to query the Gemini API.</p> <p>Based on the code earlier, what would that look like?</p> <p>Try before continuing to the next step.</p> </google-codelab-step> <google-codelab-step label="Getting ‘alt' text" duration="10" step="4"> <h2 class="step-title" id="4" data-text="Getting ‘alt' text" tabindex="-1"> 5. Getting ‘alt' text </h2> <p>How did you go? Hopefully you added in some code that looked something like this:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr"> const geminiSummary = await model .generateContent({ generationConfig, safetySettings, contents: [ { role: "user", parts: [ { text: "What is in this picture?" }, { inlineData: { mimeType: "image/png", data: base64Image, }, }, ], }, ], }) .then((result) => { return extractText(result, "text"); }); $(element).attr("alt", geminiSummary.trim()); console.log("Updated alt text for", src, "image:", geminiRead.trim()); </code></pre> <p>But what is the function ‘extractText' doing? Well, the response from the Gemini API is a nested object. To simplify extracting just the LLM's response itself, we can write the following helper function:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">function extractText(obj) { try { return obj.response.candidates[0].content.parts[0].text; } catch(e) { return undefined; } } </code></pre> <p>It's not elegant but it gets the job done for the purpose of this codelab. If you run the script on the command line again:</p> <pre translate="no" dir="ltr">node script.js </pre> <p>You should see output like this:</p> <pre translate="no" dir="ltr">Alt text is already defined: It's a cat. Alt text is already defined: It's a dog. Updated alt text for cat.png image: This is a picture of a gray and white cat sleeping in the grass. </pre> <p>At this point, our script should be looping through the images successfully and querying the Gemini API for new alt text attributes where necessary. However, to pull this asynchronous code together and truly update the HTML altogether so that we can write the final HTML output back to disk as an ‘output.html' file will require some additional changes.</p> <p>Let's rearrange the script to include an array of promises before we begin the loop. We'll prepare promises as we loop through the images, add them to the promise array and then execute all the promises in a row before finally outputting the HTML again.</p> <p>It should look like something like this:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">const cheerio = require("cheerio"); const fs = require("fs"); const { GoogleGenerativeAI } = require("@google/generative-ai"); const { join } = require("path"); const generationConfig = { temperature: 0.7, candidateCount: 1, topK: 40, topP: 0.95, maxOutputTokens: 1024, }; const safetySettings = [ { category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_NONE", }, ]; const genAI = new GoogleGenerativeAI(process.env.API_KEY); const model = genAI.getGenerativeModel({ model: "gemini-pro-vision", }); async function main() { const html = fs.readFileSync("input.html", "utf8"); const $ = cheerio.load(html); const promises = []; $("img").each(function (i, element) { // elements.push(element); promises.push( new Promise(async (resolve, reject) => { const src = $(element).attr("src"); const originalAlt = $(element).attr("alt"); if (!fs.existsSync(src)) { console.log("Image doesn't exist:", src); resolve(false); return; } const base64Image = Buffer.from(fs.readFileSync(join(__dirname, src))).toString("base64"); if (originalAlt !== undefined) { console.log("Alt text is already defined:", originalAlt); resolve(false); return; } const geminiRead = await model .generateContent({ generationConfig, safetySettings, contents: [ { role: "user", parts: [ { text: "What is in this picture? " }, { inlineData: { mimeType: "image/png", data: base64Image, }, }, ], }, ], }) .then((result) => { return extractText(result); }); $(element).attr("alt", geminiRead.trim()); console.log("Updated alt text for", src, "image:", geminiRead.trim()); resolve(true); }) ); }); Promise.all(promises).then((values) => { const updatedHTML = $.html(); fs.writeFileSync("output.html", updatedHTML); }); } main(); function extractText(obj) { try { return obj.response.candidates[0].content.parts[0].text; } catch (e) { return undefined; } } </code></pre> <p>If you re-run the script. You should now have an output.html file in your directory with the final HTML! Does your output.html look like this?</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr"><html> <body> <img src="cat.png" alt="This is a picture of a gray and white cat sleeping in the grass."> <img src="cat.png" alt="It's a cat."> <img src="cat.png" alt="It's a dog."> </body> </html> </code></pre> <p>But wait a moment. Do you see a problem? Did you notice that our original input.html file had a surprising alt tag on one of the images of the cat?</p> <p>Perhaps you did not notice. It was incredibly subtle ;-)</p> <p>That's right. One of the alt text attributes referred to the cat as a dog – outrageous.</p> <p>So we skipped that alt text because we believed it was accurate and didn't need updating. If only there was a way we could verify whether an alt text was a good enough description of an image or not... of course, this is trivial for the Gemini API.</p> <p>Let's rework the script to verify the existing alt text for each image and if the Gemini model doesn't feel it's a "good enough" description, then and only then will we replace it with Gemini's description.</p> </google-codelab-step> <google-codelab-step label="Verify first" duration="5" step="5"> <h2 class="step-title" id="5" data-text="Verify first" tabindex="-1"> 6. Verify first </h2> <p>To make this easier, we're going to write another helper function: ‘askBoolean'.</p> <p>For this function, we want to make it easy to ask Gemini a yes or no question about an image and return the response as a boolean return value.</p> <p>What might that look like?</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">async function askBoolean(question, base64Image) { return await model .generateContent({ generationConfig, safetySettings, contents: [ { role: "user", parts: [ { text: question + "\nAnswer me with either 'yes' or 'no'." }, { inlineData: { mimeType: "image/png", data: base64Image, }, }, ], }, ], }) .then((result) => { return extractText(result, "text").toLowerCase().includes("yes"); }); } </code></pre> <p>Again, this is a very simplified approach but it highlights an important part of working with an LLM. Sometimes we must make it clear to the LLM what format we want a response in. In this case, we're asking that the answer be returned as very specifically either: ‘yes' or ‘no'.</p> <p>Funnily enough, the LLM might still disobey us and almost certainly we cannot assume that the LLM will only respond with ‘yes' or ‘no'. In many cases, the LLM will elaborate as to why it has concluded with ‘yes' or ‘no' and include that in its response.</p> <p>For this reason, after extracting the text using our other helper function ‘extractText', we've simply converted all the text in the response to lower case and then we're returning true if the word ‘yes' appears anywhere in the response. Otherwise we'll return false.</p> <p>It's a simplistic solution but it will do the job for this codelab.</p> <p>How would we use this back in our script though?</p> <p>Try to rework the script yourself to leverage this function before reading the final script in the next step.</p> </google-codelab-step> <google-codelab-step label="Beauty is in the eye of the Gemini" duration="5" step="6"> <h2 class="step-title" id="6" data-text="Beauty is in the eye of the Gemini" tabindex="-1"> 7. Beauty is in the eye of the Gemini </h2> <p>Your final script should look something like this:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">const cheerio = require("cheerio"); const fs = require("fs"); const { GoogleGenerativeAI } = require("@google/generative-ai"); const { join } = require("path"); const generationConfig = { temperature: 0.7, candidateCount: 1, topK: 40, topP: 0.95, maxOutputTokens: 1024, }; const safetySettings = [ { category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_NONE", }, ]; const genAI = new GoogleGenerativeAI(process.env.API_KEY); const model = genAI.getGenerativeModel({ model: "gemini-pro-vision", }); async function main() { const html = fs.readFileSync("input.html", "utf8"); const $ = cheerio.load(html); const promises = []; $("img").each(function (i, element) { promises.push( new Promise(async (resolve, reject) => { const src = $(element).attr("src"); const originalAlt = $(element).attr("alt"); if (!fs.existsSync(src)) { console.log("Image doesn't exist:", src); resolve(false); return; } const base64Image = Buffer.from(fs.readFileSync(join(__dirname, src))).toString("base64"); let answer = false; if (originalAlt !== undefined) { answer = await askBoolean( "Does this description describe the image well? " + originalAlt, base64Image ); if (answer) { console.log("Alt text is already defined:", originalAlt); resolve(false); return; } else { console.log( "Alt text already exists but it's not good enough:", originalAlt ); } } const geminiRead = await model .generateContent({ generationConfig, safetySettings, contents: [ { role: "user", parts: [ { text: "What is in this picture? " }, { inlineData: { mimeType: "image/png", data: base64Image, }, }, ], }, ], }) .then((result) => { return extractText(result); }); $(element).attr("alt", geminiRead.trim()); console.log("Updated alt text for", src, "image:", geminiRead.trim()); resolve(true); }) ); }); Promise.all(promises).then((values) => { const updatedHTML = $.html(); fs.writeFileSync("output.html", updatedHTML); }); } main(); function extractText(obj) { try { return obj.response.candidates[0].content.parts[0].text; } catch (e) { return undefined; } } async function askBoolean(question, base64Image) { return await model .generateContent({ generationConfig, safetySettings, contents: [ { role: "user", parts: [ { text: question + "\nAnswer me with either 'yes' or 'no'." }, { inlineData: { mimeType: "image/png", data: base64Image, }, }, ], }, ], }) .then((result) => { return extractText(result, "text").toLowerCase().includes("yes"); }); } </code></pre> <p>And now, re-run the script one last time:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr"><html> <body> <img src="cat.png" alt="This is a picture of a gray and white cat sleeping in the grass."> <img src="cat.png" alt="It's a cat."> <img src="cat.png" alt="This is a picture of a gray and white cat sleeping in the grass."> </body> </html> </code></pre> <p>The incorrect dog alt text label is gone. Replaced with Gemini's interpretation of the image.</p> <p>Meanwhile the accurate existing alt text of "It's a cat." remains unchanged. Perfect.</p> </google-codelab-step> <google-codelab-step label="Reflection" duration="1" step="7"> <h2 class="step-title" id="7" data-text="Reflection" tabindex="-1"> 8. Reflection </h2> <p>Congratulations on completing the codelab! You now have a solid understanding of how to query the Gemini API using multimodal prompts combining text and images with the NodeJS SDK.</p> <p>Furthermore you've embraced a practical real-world scenario of improving the accessibility of a webpage using HTML selector queries, extracting existing HTML data and querying the Gemini model for its opinion on that existing markup.</p> <p>Where could this script go from here? An obvious next step would be to handle non-local image file references. If the src attribute doesn't match a local file on the system and if the src attribute matches the structure of a URL we could attempt to fetch the image resource dynamically from the internet and proceed from there with our script.</p> <p>For now though, we have explored a good exercise with just that humble cat.</p> </google-codelab-step> </google-codelab> <devsite-hats-survey class="nocontent" hats-id="5Djwt4Azw0iQ84LPiVd0QYQ4sHzc" listnr-id="5123748"></devsite-hats-survey> </div> <div class="devsite-floating-action-buttons"> </div> </article> <devsite-content-footer class="nocontent"> <p>Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. For details, see the <a href="https://developers.google.com/site-policies">Google Developers Site Policies</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> </devsite-content-footer> <devsite-notification > </devsite-notification> <div class="devsite-content-data"> <template class="devsite-content-data-template"> [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],[],[],[]] </template> </div> </devsite-content> </main> <devsite-footer-promos class="devsite-footer"> </devsite-footer-promos> <devsite-footer-linkboxes class="devsite-footer"> <nav class="devsite-footer-linkboxes nocontent" aria-label="Footer links"> <ul class="devsite-footer-linkboxes-list"> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Connect</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//googledevelopers.blogspot.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Blog </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://www.instagram.com/googlefordevs/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Instagram </a> </li> <li class="devsite-footer-linkbox-item"> <a href="https://www.linkedin.com/showcase/googledevelopers/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > LinkedIn </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//twitter.com/googledevs" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > X (Twitter) </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//www.youtube.com/user/GoogleDevelopers" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > YouTube </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Programs</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//www.womentechmakers.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Women Techmakers </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/community/gdg" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Google Developer Groups </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/community/experts" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Google Developer Experts </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/community/accelerators" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Accelerators </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/community/gdsc" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Google Developer Student Clubs </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Developer consoles</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//console.developers.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Google API Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.cloud.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Google Cloud Platform Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//play.google.com/apps/publish" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Google Play Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.firebase.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Firebase Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.actions.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Actions on Google Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//cast.google.com/publish" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 6)" > Cast SDK Developer Console </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//chrome.google.com/webstore/developer/dashboard" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 7)" > Chrome Web Store Dashboard </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//console.home.google.com" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 8)" > Google Home Developer Console </a> </li> </ul> </li> </ul> </nav> </devsite-footer-linkboxes> <devsite-footer-utility class="devsite-footer"> <div class="devsite-footer-utility nocontent"> <nav class="devsite-footer-sites" aria-label="Other Google Developers websites"> <a href="https://developers.google.com/" class="devsite-footer-sites-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Developers Link"> <picture> <img class="devsite-footer-sites-logo" src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/images/lockup-google-for-developers.svg" loading="lazy" alt="Google Developers"> </picture> </a> <ul class="devsite-footer-sites-list"> <li class="devsite-footer-sites-item"> <a href="//developer.android.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Android Link" > Android </a> </li> <li class="devsite-footer-sites-item"> <a href="//developer.chrome.com/home" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Chrome Link" > Chrome </a> </li> <li class="devsite-footer-sites-item"> <a href="//firebase.google.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Firebase Link" > Firebase </a> </li> <li class="devsite-footer-sites-item"> <a href="//cloud.google.com" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google Cloud Platform Link" > Google Cloud Platform </a> </li> <li class="devsite-footer-sites-item"> <a href="//ai.google.dev/" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Google AI Link" > Google AI </a> </li> <li class="devsite-footer-sites-item"> <a href="/products" class="devsite-footer-sites-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer All products Link" > All products </a> </li> </ul> </nav> <nav class="devsite-footer-utility-links" aria-label="Utility links"> <ul class="devsite-footer-utility-list"> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="/terms/site-terms" data-category="Site-Wide Custom Events" data-label="Footer Terms link" > Terms </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/privacy" data-category="Site-Wide Custom Events" data-label="Footer Privacy link" > Privacy </a> </li> <li class="devsite-footer-utility-item glue-cookie-notification-bar-control"> <a class="devsite-footer-utility-link gc-analytics-event" href="#" data-category="Site-Wide Custom Events" data-label="Footer Manage cookies link" aria-hidden="true" > Manage cookies </a> </li> <li class="devsite-footer-utility-item devsite-footer-utility-button"> <span class="devsite-footer-utility-description">Sign up for the Google for Developers newsletter</span> <a class="devsite-footer-utility-link gc-analytics-event" href="/newsletter/subscribe" data-category="Site-Wide Custom Events" data-label="Footer Subscribe link" > Subscribe </a> </li> </ul> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="de" >Deutsch</a> </li> <li role="presentation"> <a role="menuitem" lang="es" >Español</a> </li> <li role="presentation"> <a role="menuitem" lang="fr" >Français</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="ru" >Русский</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> </nav> </div> </devsite-footer-utility> <devsite-panel></devsite-panel> <devsite-concierge data-info-panel data-ai-panel data-api-explorer-panel > </devsite-concierge> </section></section> <devsite-sitemask></devsite-sitemask> <devsite-snackbar></devsite-snackbar> <devsite-tooltip ></devsite-tooltip> <devsite-heading-link></devsite-heading-link> <devsite-analytics> <script type="application/json" analytics>[{"dimensions": {"dimension5": "en", "dimension3": false, "dimension4": "Google for Developers", "dimension6": "en", "dimension11": false, "dimension1": "Signed out"}, "gaid": "UA-24532603-1", "metrics": {"ratings_count": "metric2", "ratings_value": "metric1"}, "purpose": 1}]</script> <script type="application/json" tag-management>{"at": "True", "ga4": [{"id": "G-272J68FCRF", "purpose": 1}, {"id": "G-P65P8J8YWQ", "purpose": 0}], "ga4p": [{"id": "G-272J68FCRF", "purpose": 1}], "gtm": [], "parameters": {"internalUser": "False", "language": {"machineTranslated": "False", "requested": "en", "served": "en"}, "pageType": "codelab", "projectName": "Google for Developers", "signedIn": "False", "tenant": "developers", "recommendations": {"sourcePage": "", "sourceType": 0, "sourceRank": 0, "sourceIdenticalDescriptions": 0, "sourceTitleWords": 0, "sourceDescriptionWords": 0, "experiment": ""}, "experiment": {"ids": ""}}}</script> </devsite-analytics> <devsite-badger></devsite-badger> <script nonce="harshvETF4FPYk1RJLilBEb2EjlwQY"> (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; E.parentNode.insertBefore(t,E);})(window, document, 'script', 'https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/js/app_loader.js', '[1,"en",null,"/js/devsite_app_module.js","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers","https://developers-dot-devsite-v2-prod.appspot.com",1,null,["/_pwa/developers/manifest.json","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/images/video-placeholder.svg","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/images/favicon-new.png","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/developers/images/lockup-new.svg","https://fonts.googleapis.com/css?family=Google+Sans:400,500|Roboto:400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"],1,null,[1,6,8,12,14,17,21,25,50,52,63,70,75,76,80,87,91,92,93,97,98,100,101,102,103,104,105,107,108,109,110,112,113,117,118,120,122,124,125,126,127,129,130,131,132,133,134,135,136,138,140,141,147,148,149,151,152,156,157,158,159,161,163,164,168,169,170,179,180,182,183,186,191,193,196],"AIzaSyAP-jjEJBzmIyKR4F-3XITp8yM9T1gEEI8","AIzaSyB6xiKGDR5O3Ak2okS4rLkauxGUG7XP0hg","developers.google.com","AIzaSyAQk0fBONSGUqCNznf6Krs82Ap1-NV6J4o","AIzaSyCCxcqdrZ_7QMeLCRY20bh_SXdAYqy70KY",null,null,null,["Profiles__enable_developer_profiles_callout","Profiles__enable_release_notes_notifications","Profiles__enable_dashboard_curated_recommendations","Cloud__enable_legacy_calculator_redirect","Profiles__enable_profile_collections","MiscFeatureFlags__enable_firebase_utm","Experiments__reqs_query_experiments","Cloud__enable_cloud_facet_chat","TpcFeatures__enable_mirror_tenant_redirects","Analytics__enable_clearcut_logging","Cloud__enable_cloud_shell","MiscFeatureFlags__developers_footer_dark_image","BookNav__enable_tenant_cache_key","Profiles__enable_complete_playlist_endpoint","MiscFeatureFlags__enable_project_variables","Concierge__enable_concierge_restricted","Search__enable_page_map","Significatio__enable_by_tenant","Search__enable_dynamic_content_confidential_banner","Profiles__require_profile_eligibility_for_signin","Profiles__enable_awarding_url","Cloud__enable_cloud_dlp_service","MiscFeatureFlags__enable_view_transitions","Search__enable_ai_search_summaries_restricted","Cloud__enable_llm_concierge_chat","Cloud__enable_free_trial_server_call","MiscFeatureFlags__emergency_css","Search__enable_ai_eligibility_checks","DevPro__enable_developer_subscriptions","MiscFeatureFlags__developers_footer_image","Profiles__enable_public_developer_profiles","CloudShell__cloud_shell_button","Cloud__enable_cloudx_ping","TpcFeatures__enable_required_headers","Profiles__enable_recognition_badges","Search__enable_ai_search_summaries","Concierge__enable_pushui","Concierge__enable_concierge","Cloud__enable_cloud_shell_fte_user_flow","Profiles__enable_page_saving","MiscFeatureFlags__enable_variable_operator","Cloud__enable_cloudx_experiment_ids","CloudShell__cloud_code_overflow_menu","Search__enable_suggestions_from_borg","MiscFeatureFlags__enable_explain_this_code","Profiles__enable_completecodelab_endpoint","DevPro__enable_cloud_innovators_plus","EngEduTelemetry__enable_engedu_telemetry"],null,null,"AIzaSyBLEMok-5suZ67qRPzx0qUtbnLmyT_kCVE","https://developerscontentserving-pa.clients6.google.com","AIzaSyCM4QpTRSqP5qI4Dvjt4OAScIN8sOUlO-k","https://developerscontentsearch-pa.clients6.google.com",1,4,null,"https://developerprofiles-pa.clients6.google.com",[1,"developers","Google for Developers","developers.google.com",null,"developers-dot-devsite-v2-prod.appspot.com",null,null,[1,1,[1],null,null,null,null,null,null,null,null,[1],null,null,null,null,null,null,[1],[1,null,null,[1,20],"/recommendations/information"],null,null,null,[1,1,1],[1,1,null,1,1]],null,[null,null,null,null,null,null,"/images/lockup-new.svg","/images/touchicon-180-new.png",null,null,null,null,1,null,null,null,null,null,null,null,null,1,null,null,null,"/images/lockup-dark-theme-new.svg",[]],[],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[6,1,14,15,20,22,23,29,32,36],null,[[null,null,null,[3,7,10,2,39,17,4,32,24,11,12,13,34,15,25],null,null,[1,[["docType","Choose a content type",[["Tutorial",null,null,null,null,null,null,null,null,"Tutorial"],["Guide",null,null,null,null,null,null,null,null,"Guide"],["Sample",null,null,null,null,null,null,null,null,"Sample"]]],["product","Choose a product",[["Android",null,null,null,null,null,null,null,null,"Android"],["ARCore",null,null,null,null,null,null,null,null,"ARCore"],["ChromeOS",null,null,null,null,null,null,null,null,"ChromeOS"],["Firebase",null,null,null,null,null,null,null,null,"Firebase"],["Flutter",null,null,null,null,null,null,null,null,"Flutter"],["Assistant",null,null,null,null,null,null,null,null,"Google Assistant"],["GoogleCloud",null,null,null,null,null,null,null,null,"Google Cloud"],["GoogleMapsPlatform",null,null,null,null,null,null,null,null,"Google Maps Platform"],["GooglePay",null,null,null,null,null,null,null,null,"Google Pay & Google Wallet"],["GooglePlay",null,null,null,null,null,null,null,null,"Google Play"],["Tensorflow",null,null,null,null,null,null,null,null,"TensorFlow"]]],["category","Choose a topic",[["AiAndMachineLearning",null,null,null,null,null,null,null,null,"AI and Machine Learning"],["Data",null,null,null,null,null,null,null,null,"Data"],["Enterprise",null,null,null,null,null,null,null,null,"Enterprise"],["Gaming",null,null,null,null,null,null,null,null,"Gaming"],["Mobile",null,null,null,null,null,null,null,null,"Mobile"],["Web",null,null,null,null,null,null,null,null,"Web"]]]]]],[1,1],null,1],[[["UA-24532603-1"],["UA-22084204-5"],null,null,["UA-24532603-5"],null,null,[["G-272J68FCRF"],null,null,[["G-272J68FCRF",2]]],[["UA-24532603-1",2]],null,[["UA-24532603-5",2]],null,1],[[4,3],[11,8],[16,13],[5,4],[12,9],[3,2],[13,10],[1,1],[14,11],[15,12],[6,5]],[[1,1],[2,2]]],null,4,null,null,null,null,null,null,null,null,null,null,null,null,null,"developers.devsite.google"],null,"pk_live_5170syrHvgGVmSx9sBrnWtA5luvk9BwnVcvIi7HizpwauFG96WedXsuXh790rtij9AmGllqPtMLfhe2RSwD6Pn38V00uBCydV4m"]') </script> <devsite-a11y-announce></devsite-a11y-announce> </body> </html>