2026, Jan 07 21:00

How to Reliably Switch to a Login iframe in Selenium: ditch absolute XPath, use stable locators and waits

Troubleshooting Selenium iframe switching: avoid brittle XPath, target the login iframe via stable attributes, and use WebDriverWait for reliable automation.

Switching into an iframe is a common Selenium task, yet it often breaks when the target frame is located with a brittle XPath. That’s exactly what happens when trying to access the login iframe on https://www.steelmarketupdate.com/: a previously working absolute XPath no longer hits the right element, and even iterating by index doesn’t help.

Reproducing the issue

The attempt below targets an iframe by an absolute, position-dependent XPath. It used to work, but now fails to locate the correct frame.

from selenium.webdriver.common.by import By
agent.switch_to.frame(agent.find_element(By.XPATH, "/html/body/div[6]/div/iframe"))

What’s actually going on

The locator hinges on the exact DOM structure and a fixed index under /html/body/div[6]/div/iframe. When that structure no longer matches the real page, Selenium can’t find the desired frame. Counting all iframes on the page and switching by index also doesn’t resolve it. The working approach is to target the specific login iframe that appears after clicking the Log In button and to use a stable attribute in the locator.

The fix: target the right iframe and wait for it

Use a relative XPath that identifies the login iframe by a reliable attribute and wait until the frame is present and ready to switch to. There are two shown options: a locator by an id that contains piano, or a position-based locator for the third iframe in the DOM.

# Option 1: locate the iframe by an ID that contains "piano"
By.XPATH, "//iframe[contains(@id,'piano')]"
# Option 2: locate the 3rd iframe in the DOM
By.XPATH, "(//iframe)[3]"

For a direct switch using the attribute-based locator:

navigator.switch_to.frame(navigator.find_element(By.XPATH, "//iframe[contains(@id,'piano')]") )

Working example with waits

The sequence below opens the site, clicks the Log In entry, switches into the correct iframe when it becomes available, fills the email and password fields, and then returns to the main document.

import time
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get("https://www.steelmarketupdate.com/")
browser.maximize_window()
sync = WebDriverWait(browser, 10)
# Click the Log In element
sync.until(EC.element_to_be_clickable((By.XPATH, "(//li[@id='pp-subs-login'])[1]"))).click()
# Switch into the login iframe once it's available
sync.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[contains(@id,'piano')]")))
# Fill in credentials
sync.until(EC.element_to_be_clickable((By.NAME, "email"))).send_keys("testEmail")
sync.until(EC.element_to_be_clickable((By.XPATH, "//input[@aria-label='password']"))).send_keys("testPassword")
# Back to the main document
browser.switch_to.default_content()
# Pause briefly to observe the result
time.sleep(10)

Why this matters

Frame handling is a frequent source of flakiness in UI tests and automation scripts. Relying on absolute XPaths or raw indexes couples your code to the exact DOM shape, which tends to change. Targeting the correct iframe with a robust locator and using explicit waits for both the frame and inner elements makes the interaction predictable and resilient.

Takeaways

When a previously working iframe XPath stops finding the element, switch to a stable locator and wait for the frame to be available before interacting with it. On the login flow described above, selecting the frame via //iframe[contains(@id,'piano')] and using WebDriverWait to both enter and exit the frame path leads to a consistently working script.