@appium/mcp-documentation 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/LICENSE +201 -0
  3. package/README.md +126 -0
  4. package/dist/answer-appium.d.ts +8 -0
  5. package/dist/answer-appium.d.ts.map +1 -0
  6. package/dist/answer-appium.js +38 -0
  7. package/dist/answer-appium.js.map +1 -0
  8. package/dist/appium-skills.d.ts +5 -0
  9. package/dist/appium-skills.d.ts.map +1 -0
  10. package/dist/appium-skills.js +168 -0
  11. package/dist/appium-skills.js.map +1 -0
  12. package/dist/index.d.ts +31 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +69 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/logger.d.ts +4 -0
  17. package/dist/logger.d.ts.map +1 -0
  18. package/dist/logger.js +5 -0
  19. package/dist/logger.js.map +1 -0
  20. package/dist/markdown-header-splitter.d.ts +32 -0
  21. package/dist/markdown-header-splitter.d.ts.map +1 -0
  22. package/dist/markdown-header-splitter.js +180 -0
  23. package/dist/markdown-header-splitter.js.map +1 -0
  24. package/dist/paths.d.ts +2 -0
  25. package/dist/paths.d.ts.map +1 -0
  26. package/dist/paths.js +22 -0
  27. package/dist/paths.js.map +1 -0
  28. package/dist/plugin.d.ts +19 -0
  29. package/dist/plugin.d.ts.map +1 -0
  30. package/dist/plugin.js +18 -0
  31. package/dist/plugin.js.map +1 -0
  32. package/dist/reasoning-rag.d.ts +89 -0
  33. package/dist/reasoning-rag.d.ts.map +1 -0
  34. package/dist/reasoning-rag.js +282 -0
  35. package/dist/reasoning-rag.js.map +1 -0
  36. package/dist/scripts/eval-documentation-rag.d.ts +50 -0
  37. package/dist/scripts/eval-documentation-rag.d.ts.map +1 -0
  38. package/dist/scripts/eval-documentation-rag.js +287 -0
  39. package/dist/scripts/eval-documentation-rag.js.map +1 -0
  40. package/dist/scripts/generate-embeddings-cache.d.ts +13 -0
  41. package/dist/scripts/generate-embeddings-cache.d.ts.map +1 -0
  42. package/dist/scripts/generate-embeddings-cache.js +24 -0
  43. package/dist/scripts/generate-embeddings-cache.js.map +1 -0
  44. package/dist/scripts/rag-eval-dataset.json +516 -0
  45. package/dist/scripts/simple-index-documentation.d.ts +21 -0
  46. package/dist/scripts/simple-index-documentation.d.ts.map +1 -0
  47. package/dist/scripts/simple-index-documentation.js +77 -0
  48. package/dist/scripts/simple-index-documentation.js.map +1 -0
  49. package/dist/scripts/simple-query-documentation.d.ts +13 -0
  50. package/dist/scripts/simple-query-documentation.d.ts.map +1 -0
  51. package/dist/scripts/simple-query-documentation.js +52 -0
  52. package/dist/scripts/simple-query-documentation.js.map +1 -0
  53. package/dist/sentence-transformers-embeddings.d.ts +40 -0
  54. package/dist/sentence-transformers-embeddings.d.ts.map +1 -0
  55. package/dist/sentence-transformers-embeddings.js +119 -0
  56. package/dist/sentence-transformers-embeddings.js.map +1 -0
  57. package/dist/simple-pdf-indexer.d.ts +47 -0
  58. package/dist/simple-pdf-indexer.d.ts.map +1 -0
  59. package/dist/simple-pdf-indexer.js +572 -0
  60. package/dist/simple-pdf-indexer.js.map +1 -0
  61. package/dist/tests/__mocks__/@appium/support.d.ts +92 -0
  62. package/dist/tests/__mocks__/@appium/support.d.ts.map +1 -0
  63. package/dist/tests/__mocks__/@appium/support.js +66 -0
  64. package/dist/tests/__mocks__/@appium/support.js.map +1 -0
  65. package/dist/tests/appium-skills.test.d.ts +2 -0
  66. package/dist/tests/appium-skills.test.d.ts.map +1 -0
  67. package/dist/tests/appium-skills.test.js +26 -0
  68. package/dist/tests/appium-skills.test.js.map +1 -0
  69. package/dist/tests/plugin.test.d.ts +2 -0
  70. package/dist/tests/plugin.test.d.ts.map +1 -0
  71. package/dist/tests/plugin.test.js +18 -0
  72. package/dist/tests/plugin.test.js.map +1 -0
  73. package/dist/tests/simple-pdf-indexer.test.d.ts +2 -0
  74. package/dist/tests/simple-pdf-indexer.test.d.ts.map +1 -0
  75. package/dist/tests/simple-pdf-indexer.test.js +37 -0
  76. package/dist/tests/simple-pdf-indexer.test.js.map +1 -0
  77. package/dist/tool-response.d.ts +4 -0
  78. package/dist/tool-response.d.ts.map +1 -0
  79. package/dist/tool-response.js +12 -0
  80. package/dist/tool-response.js.map +1 -0
  81. package/dist/tools.d.ts +3 -0
  82. package/dist/tools.d.ts.map +1 -0
  83. package/dist/tools.js +3 -0
  84. package/dist/tools.js.map +1 -0
  85. package/dist/uploads/documents.json +1 -0
  86. package/package.json +84 -0
  87. package/scripts/zip-assets.mjs +75 -0
  88. package/src/resources/submodules.zip +0 -0
@@ -0,0 +1 @@
1
+ [{"pageContent":"## Code of Conduct\n\n## Code of Conduct > ### What is this code of conduct for?\n\nAppium is a piece of technology, but **the core of the Appium community is the people in it**. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, gender identity and expression, sexual orientation, ability, physical appearance, body size, race, age, socioeconomic status, religion (or lack thereof), or other marginalized aspect of community members. We expect all members of the Appium community to abide by this Code of Conduct whenever interacting in Appium venues (pull requests, GitHub issues, 1-1 or group chat, meetups, conferences, etc...)\n\n## Code of Conduct > ### Examples of inappropriate behavior\n\nBecause we come from a variety of backgrounds, we don't want to assume that everyone has the same assumptions about what is and isn't appropriate. Here are some examples of inappropriate behavior that are incompatible with our community's ethos:\n\n* Spamming, trolling, intentionally disrupting conversations, or irrelevant solicitation or advertisement\n* Making demeaning or discriminatory comments\n* Making negative assumptions about someone's background, abilities, or intentions\n* Harassing or stalking individuals (online or in person)\n* Giving someone unwelcome sexual attention or making unwelcome physical contact (in the case of an IRL event)\n* Sharing sexual images or using sexually explicit language\n\nIn general: treat others how you would like to be treated, were you in their place. Don't be a jerk. _Do_ ask questions. _Do_ keep conflicts productively focused on technical issues. _Do_ think before you speak; remember that what is perceived as a funny witticism in your group of friends might be hurtful or reinforce hurtful stereotypes in the context of our diverse online community. _Do_ remember that we are all people, not robots, and all equally deserving of sensitivity and respect. (If and when robots join our community, let's treat them with respect too!)","metadata":{"headerPath":"## Code of Conduct","sectionCount":3,"filename":"CONDUCT.md","relativePath":"appium/CONDUCT.md"}},{"pageContent":"## Code of Conduct > ### What will organizers do about inappropriate behavior?\n\nIf we notice you doing or saying something inappropriate, an organizer will explain why it's inappropriate and ask you to stop. We won't demonize or vilify you. But please do stop the inappropriate behavior so we can get back to writing and discussing code in a safe environment. If you have philosophical disagreements about what's actually inappropriate, please take them to a separate public or private conversation with an Appium maintainer so we don't turn pull requests into an ethics debate.\n\nIf you keep doing unacceptable things, we'll likely ban you, report you to GitHub, or take other appropriate action.\n\n## Code of Conduct > ### What if I see or am subject to what feels like inappropriate behavior?\n\nLet us know! Please notify a community organizer as soon as possible. Full contact information is listed in the [Contact Info](#contact-info) section of this document. All communications will be kept strictly confidential, unless otherwise required by law. No issue will be considered too inconsequential or unimportant for us to have a conversation about.\n\n## Code of Conduct > ### Contact Info\n\nIf you need to report an incident, please contact any of the following organizers directly:\n\n* Isaac Murchie [email](mailto:isaac@saucelabs.com) [twitter](https://twitter.com/imurchie)\n* Jonathan Lipps [email](mailto:jlipps@saucelabs.com) [twitter](https://twitter.com/jlipps)\n\n## Code of Conduct > ### Credit, License, and Attribution\n\nThis Code of Conduct is distributed under a [Creative Commons Attribution-ShareAlike license](http://creativecommons.org/licenses/by-sa/3.0/).\n\nIt's inspired among other things by:\n* [Citizen Code of Conduct](http://citizencodeofconduct.org/)\n* [npmjs](https://www.npmjs.com/policies/conduct)\n* [Geek Feminism](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy)\n* [Ashe Dryden](http://www.ashedryden.com/blog/codes-of-conduct-101-faq)\n* [Model View Culture](https://modelviewculture.com/issues/events)\n* [Open Source & Feelings](http://osfeels.com/conduct).","metadata":{"headerPath":"## Code of Conduct > ### What will organizers do about inappropriate behavior?","sectionCount":4,"filename":"CONDUCT.md","relativePath":"appium/CONDUCT.md"}},{"pageContent":"# Appium Project Governance\n\nThe Appium Project wants as much as possible to operate using procedures that\nare fair, open, inviting, and ultimately good for the community. For that\nreason we find it valuable to codify some of the ways that the Project goes\nabout its day-to-day business. We want to make sure that no matter who you are,\nyou have the opportunity to contribute to Appium. We want to make sure that no\none corporation can exert undue influence on the community or hold the Project\nhostage. And likewise we want to make sure that corporations which benefit from\nAppium are also incentivized to give back.\n\n# Appium Project Governance > ### The Technical Committee\n\nThe project is officially led by a Technical Committee (TC), currently\nconsisting of:\n\n* [@jlipps](https://github.com/jlipps)\n* [@mykola-mokhnach](https://github.com/mykola-mokhnach)\n* [@eglitise](https://github.com/eglitise)\n* [@KazuCocoa](https://github.com/KazuCocoa)\n\nThey all represent different companies and different types of contribution to\nthe Appium Project. The TC is responsible for high-level decisions (like\nestablishing a feature roadmap, accepting sponsorship, organizing conferences,\netc...), adjudicating conflicts between members of the community, and making\nchanges to the project's governance processes.\n\n* Membership in the TC is granted by unanimous vote of current TC members.\n* TC members can step down at any time.\n* No more than 1/3 (or 2, whichever is higher) of TC members may belong to the same company.\n* Changes to project governance require unanimous vote of the TC.","metadata":{"headerPath":"# Appium Project Governance","sectionCount":2,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"# Appium Project Governance > ### Project Committers\n\nMost of the project maintenance is handled by committers, community members who\nhave been granted commit access to the Appium organization on GitHub. The\nresponsibilities of committers include: reviewing and merging pull requests,\nwalking through changes with developers, weighing in on architectural issues,\nand so on.","metadata":{"headerPath":"# Appium Project Governance > ### Project Committers","sectionCount":1,"recursiveSplit":true,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"# Appium Project Governance > ### Project Committers\n\n* Any two TC members can decide to make someone a project committer, providing that person has shown an appropriate understanding of the Appium codebase through prior contributions of code.\n* In general any committer can review and merge a PR. In general committers should only merge code they are qualified to review, which might entail pinging another committer who has greater ownership over a specific code area.\n* Debates between committers about whether code should be merged should happen in GitHub pull requests.\n* Proposals for large changes to the project's code (architectural changes, etc...) should be brought forward as a GitHub issue (with the label `Proposal`), and all committers should be pinged so they can weigh in on the discussion if desired. Substantial changes, whether in proposal stage or in pull request stage should be signed off on by 1 TC member and at least 2 other committers. To assist in the discussion, a small proof of concept can be undertaken on a subset of the Appium ecosystem and raised as a strawman PR, to give flesh to the proposal and make discussion more helpfully concrete.\n* In general disputes about code should be resolved by discussion, not votes. If there is substantial disagreement, aim for consensus. If that is not possible, committers can bring the dispute to the TC for a vote, with the outcome determined by a majority.\n* Any committer can decide to close a PR or issue if they determine the change doesn't suit the project.\n* Appium has a large ecosystem of repositories. Some are 'core' in the sense of being central subpackages with a lot of traffic like `appium/appium` or `appium/appium-ios-driver`. Others are 'peripheral' in the sense of receiving few changes, being maintained by 1 person or no one, etc..., like `appium/ruby_lib` or `appium/appium_thor` For 'core' repos, committers should not merge their own code straightaway. Like all contributors they should open a PR and get a +1 from another committer. For 'peripheral' repos for which they are the sole maintainer or for which they have a good understanding, it is obtuse to insist on another contributor's +1 and this rule should be relaxed in that case. In sum: use good judgment and don't ram code through without a review when you can help it.\n\nThe current committers are (along with their primary areas(s) of ownership or maintenance):","metadata":{"headerPath":"# Appium Project Governance > ### Project Committers","sectionCount":1,"recursiveSplit":true,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"# Appium Project Governance > ### Project Committers\n\nThe current committers are (along with their primary areas(s) of ownership or maintenance):\n\n* [@dan-maor](https://github.com/Dan-Maor) - XCUITest driver and iOS internals\n* [@dor-bl](https://github.com/Dor-bl) - DotNet client\n* [@eglitise](https://github.com/eglitise) - Appium server, Inspector\n* [@jlipps](https://github.com/jlipps) - Appium server, Inspector\n* [@kazucocoa](https://github.com/KazuCocoa) - all Appium projects\n* [@laolubenson](https://github.com/laolubenson) - DotNet client\n* [@mwakizaka](https://github.com/mwakizaka) - XCUITest driver\n* [@mykola-mokhnach](https://github.com/mykola-mokhnach) - all Appium projects\n* [@rerorero](https://github.com/rerorero) - XCUITest/UIA2 driver\n* [@saikrishna321](https://github.com/saikrishna321) - Java client\n* [@srinivasantarget](https://github.com/SrinivasanTarget) - Java client\n* [@tomriddly](https://github.com/tomriddly) - appium-ios-device\n* [@valfirst](https://github.com/valfirst) - Java client\n\nSee [Emeritus Contributors](#emeritus-contributors) below for a list of people who formerly made\nsignificant contributions to the project but are no longer actively committing.","metadata":{"headerPath":"# Appium Project Governance > ### Project Committers","sectionCount":1,"recursiveSplit":true,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"# Appium Project Governance > ### Other Contributors\n\nOther, less formal, kinds of contribution are outlined in our [Contributing Guide](https://appium.io/docs/en/latest/contributing/).\nWe also very much appreciate those who spend their valuable time assisting with the [Appium forums](https://discuss.appium.io).\nCurrent high-level forum contributors and mods include:\n\n* [aleksei](https://discuss.appium.io/u/aleksei/summary)\n* [wreed](https://discuss.appium.io/u/wreed/summary)","metadata":{"headerPath":"# Appium Project Governance > ### Other Contributors","sectionCount":1,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"# Appium Project Governance > ### Sponsorship\n\nThe Appium project welcomes the sponsorship of individuals and organizations. There are two types\nof sponsorship: those related to contributions of Appium maintenance and leadership, and those\nrelated to contributions of funds. Both are extremely important to the ongoing health of the\nproject. Financial sponsorship is mediated through our [OpenCollective page](https://opencollective.com/appium).\nSponsorship tiers and benefits are described below:\n\n- **Development Partners**: The primary need of any open source project is for sustained maintenance and contributorship. Companies that officially sponsor such development with dedicated employee time are recognized as Development Partners, and receive the same benefits as the highest tier of financial sponsorship. To be considered a Development Partner, a company must devote at least 50% of a full-time employee's time to Appium maintenance. This means that the contributors designated by the company must have been appointed as \"committers\" in good standing of one or more core Appium repositories. (See above for a description of how to become a committer).\n- **Strategic Partners**: Representing the highest tier of ongoing financial support for the project, Strategic Partners are what make our compensation scheme for contributors possible, and we thank them for their significant investment into the project! More than financial contribution, Strategic Partners help elevate Appium's position in the industry through marketing and evangelism efforts, and partner with the Appium team to help make Appium better. Along with the Development Partners, Strategic Partners have their logos displayed prominently on our website, and have the ability to link to their Appium-related products in a few relevant places in our documentation.\n- **Gold, Silver, and Bronze Sponsors**: these sponsorship levels correspond to different amounts of recurring financial contribution that generously support our contributor compensation scheme. Sponsors at these levels also have the opportunity to display their logo on our website.\n- **Backers**: individuals who benefit from the Appium project can also donate on a one-time or recurring basis, at any amount, and will be recognized as Backers for their contribution!\n\nTo become a sponsor at one of these levels, follow the process indicated at the [OpenCollective\npage](https://opencollective.com/appium).","metadata":{"headerPath":"# Appium Project Governance > ### Sponsorship","sectionCount":1,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"# Appium Project Governance > ### Compensation Scheme\n\nWith funds received through sponsorship, the Appium project wants to incentivize contributions of\ncode, documentation efforts, maintenance, and project leadership. We have developed a scheme\n(inspired by one developed at the [WebdriverIO](https://github.com/webdriverio/webdriverio)\nproject) for disbursing funds on a monthly basis to those who contribute to the project, as well as\nsome other \"upstream\" open source projects.\n\nEach month, 15% of sponsorship funds received will be donated to upstream projects, based on the\ndiscretion of the current TC. At this point, no attempt will be made to formalize quantitative\nnotions of relevance. If you manage a project upstream of Appium and would like to be considered as\npart of this donation group, give us a shout!\n\nOf the remaining 85% of sponsorship funds, 70% (roughly 60% of the original total) will go to\nproject Committers (i.e., those in a role of maintenance), and 30% (roughly 25% of the original\ntotal) will go to Contributors (i.e., those making one-off or periodic contributions). The way that\nCommitters and Contributors are paid for their efforts differs.\n\nFor Committers, each Committer will keep a monthly time sheet of hours contributed to the project.\nAt the end of each month, the hours tracked from all Committers will be totalled, and then the\nCommitter-allocated funds will be disbursed (via OpenCollective) on a pro rata basis. Within this\nscheme, Committers agree not to submit hours worked as part of their employment with a Development\nPartner (since this is part of the \"sponsorship\" contribution of the Development Partner).\n\nFor Contributors, when they make contributions which are successfully merged into the project,\na Committer can discretionarily assign a \"value tier\" to the contribution. The \"value tiers\" and\ncorresponding payouts are as follows:\n\n- XS: a trivial change (e.g. a typo change or applying of an automatically suggested security\npatch). \\$0.\n- S: a small but useful change. \\$25.\n- M: a medium-small or slightly more complex change. \\$50.\n- L: a very valuable or sizable change. \\$100.\n- XL: a massive change or set of changes. \\$500.","metadata":{"headerPath":"# Appium Project Governance > ### Compensation Scheme","sectionCount":1,"recursiveSplit":true,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"# Appium Project Governance > ### Compensation Scheme\n\nAt the end of each month, Committers will total up the number of changes receiving potential\npayout. If the total amount of funds allocated for Contributor payout exceeds the total amount to\nbe paid, then each Contributor will receive an OpenCollective link to claim their funds. If not\nenough funds exist to cover all payouts, then the payout amounts will be scaled down in a pro rata\nfashion.\n\nThe scope for Committer or Contributor payouts is work completed within any \"core\" Appium\nrepository (i.e., those officially maintained by the Appium team, residing within the Appium\norganization on GitHub, under `https://github.com/appium`).\n\nSome disclaimers: Payments will happen exclusively via OpenCollective. Recipients of funds are\nresponsible for maintaining their OpenCollective account in a fashion where funds can be disbursed,\nand are responsible for any and all tax, financial, or legal consequences of receiving money in\nthis way. Receipt of funds from this scheme holds the Appium project and the OpenJS Foundation free\nof any claim or obligation. While this document exists to clearly and publicly lay out the terms\nunder which payments are generally made, the TC retains the right to grant or withhold funding on\na discretionary of special basis. Basically, this scheme is run at the project's discretion, and is\nnot a public service. Making contributions to the project under this scheme does not obligate the\nproject to pay you for such work, or otherwise compensate you in any way.","metadata":{"headerPath":"# Appium Project Governance > ### Compensation Scheme","sectionCount":1,"recursiveSplit":true,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"# Appium Project Governance > ### Raising Issues Related to Governance\n\nThis governance model necessarily leaves many situations unspecified. If\nquestions arise as to how a given situation should proceed according to the\noverall goals of the project, the best thing to do is to open a GitHub issue\nand ping the TC members.\n\n# Appium Project Governance > ### Emeritus Contributors\n\n* [@aluedeke](https://github.com/aluedeke)\n* [@astro03](https://github.com/Astro03)\n* [@bayandin](https://github.com/bayandin)\n* [@boneskull](https://github.com/boneskull)\n* [@bootstraponline](https://github.com/bootstraponline)\n* [@dandoveralba](https://github.com/dandoveralba)\n* [@ddkjin](https://github.com/ddkjin)\n* [@drpy](https://github.com/drpy)\n* [@dylanLacey](https://github.com/DylanLacey)\n* [@filmaj](https://github.com/filmaj)\n* [@gempesaw](https://github.com/gempesaw)\n* [@hugs](https://github.com/hugs)\n* [@imurchie](https://github.com/imurchie)\n* [@jamieEdge](https://github.com/JamieEdge)\n* [@jdeff](https://github.com/jdeff)\n* [@jonahss](https://github.com/Jonahss)\n* [@maudineormsby](https://github.com/maudineormsby)\n* [@moizjv](https://github.com/moizjv)\n* [@peepa](https://github.com/peepa)\n* [@penguinho](https://github.com/penguinho)\n* [@sbonebrake](https://github.com/sbonebrake)\n* [@scottdixon](https://github.com/scottdixon)\n* [@sebv](https://github.com/sebv)\n* [@sravanmedarapu](https://github.com/sravanmedarapu)\n* [@stuartbrussell-intuit](https://github.com/stuartbrussell-intuit)\n* [@tikhomirovSergey](https://github.com/TikhomirovSergey)\n* [@titusfortner](https://github.com/titusfortner)\n* [@vgrigoruk](https://github.com/vgrigoruk)\n* [@vmaxim](https://github.com/vmaxim)","metadata":{"headerPath":"# Appium Project Governance > ### Raising Issues Related to Governance","sectionCount":2,"filename":"GOVERNANCE.md","relativePath":"appium/GOVERNANCE.md"}},{"pageContent":"Google Summer of Code Ideas\n=====\n\nAppium is excited to participate as a [Google Summer of Code](https://summerofcode.withgoogle.com/) sponsor project. Here's a fun list of ideas that a Summer of Code student participant can use as a foundation for thinking about what to contribute to Appium!\n\n|Idea|Description|\n|----|-----------|\n|Apple tvOS Support|Our users have been asking for an Appium driver for Apple tvOS apps. Is this possible? We're not entirely sure! Why not be awesome and build it?|\n|Test App revamp|Appium uses a number of poorly-designed mobile applications in its own testing. We have to use a variety of apps because we need to test that Appium can automate all the various controls and platform features that mobile vendors provide. Really what we need is one cross-platform app (or one app per platform) that exhibit all and only the features we need to test. This would be a fun project to build some mobile apps used for testing and also demoing Appium at events and in training videos, etc...|\n|Tooling and Performance|We haven't instrumented Appium with very many performance metrics, and don't really know if we're missing some low-hanging fruit in terms of performance. Maybe you can help us do that?|\n|Babel|We have a lot of repos, and they're all on a really old version of Babel. They all need to stay in sync. How can we make this situation better, and upgrade to the latest and greatest?|\n|Unity3d Driver|Historically, Appium hasn't been great at automating games. We don't have any particular support for the frameworks used to create games. Unity is a popular one, for example. What if we could write an Appium driver that talked to an embedded process in a test version of a Unity game, that allowed us to find and interact with 3d elements? It would be amazing! You can also be amazing and lead Appium into this new world.|\n|Testing the Internet of Things|Appium's architecture makes it dead simple to integrate drivers for automating new technologies. What about _really_ new technologies like IoT devices? Help to redefine the semantics of the WebDriver protocol for use with IoT, and build a driver for an IoT device to prove it out.|\n|Driver for X|Have an idea of something else Appium could automate that it doesn't already? Build a driver for it! This would involve some awesome Node.js code, plus whatever else is needed to integrate with the platform you have in mind.|","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"IDEAS.md","relativePath":"appium/IDEAS.md"}},{"pageContent":"Hopefully this gives you some ideas of fun projects that would be substantial and long-lasting contributions to the Appium community.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"IDEAS.md","relativePath":"appium/IDEAS.md"}},{"pageContent":"<p align=\"center\">\n <a href=\"https://appium.io/\">\n <img alt=\"Appium\" src=\"https://raw.githubusercontent.com/appium/appium/master/packages/appium/docs/overrides/assets/images/appium-logo-horiz.png\" width=\"500\">\n </a>\n</p>\n<p align=\"center\">\n Cross-platform test automation for native, hybrid, mobile web and desktop apps.\n</p>\n\n<div align=\"center\">\n\n[![NPM version](https://badge.fury.io/js/appium.svg)](https://npmjs.org/package/appium)\n[![Monthly Downloads](https://img.shields.io/npm/dm/appium.svg)](https://npmjs.org/package/appium)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)\n[![StandWithUkraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://github.com/vshymanskyy/StandWithUkraine/)\n[![CeasefireInGaza](https://img.shields.io/badge/Ceasefire_Now-%F0%9F%87%B5%F0%9F%87%B8-red?style=flat)](https://www.unrwa.org/)\n\n</div>\n\n***\n\n<p align=\"center\"><b>\n <a href=\"https://appium.io\">Documentation</a> |\n <a href=\"https://appium.io/docs/en/latest/intro/\">Get Started</a> |\n <a href=\"https://appium.io/docs/en/latest/ecosystem/\">Ecosystem</a> |\n <a href=\"https://github.com/appium/appium/blob/master/packages/appium/CHANGELOG.md\">Changelog</a> |\n <a href=\"https://appium.io/docs/en/latest/contributing/\">Contributing Guide</a> |\n <a href=\"https://discuss.appium.io\">Discussion Forum</a>\n</b></p>\n\n***\n\nAppium is an open-source automation framework that provides\n[WebDriver](https://www.w3.org/TR/webdriver/)-based automation possibilities for a wide range of\ndifferent mobile, desktop and IoT platforms. Appium is modular and extensible, and supports multiple\nprogramming languages, which means there is an entire ecosystem of related software:\n* [__Drivers__](#drivers) add support for automating specific platforms\n* [__Clients__](#clients) allow writing Appium tests in your programming language of choice\n* [__Plugins__](#plugins) allow to further extend Appium functionality\n\n## Upgrading From Older Versions\n\nThe Appium team only provides support for the most recent version of Appium. If you wish to upgrade from\nan older major Appium version, please refer to the migration guides:\n\n* [Appium v2 to v3](https://appium.io/docs/en/latest/guides/migrating-2-to-3/)\n* [Appium v1 to v2](https://appium.io/docs/en/latest/guides/migrating-1-to-2/)","metadata":{"headerPath":"","sectionCount":2,"filename":"README.md","relativePath":"appium/README.md"}},{"pageContent":"## Installation\n\nAppium can be installed using `npm` (other package managers are not currently supported). Please\ncheck the [installation docs](http://appium.io/docs/en/latest/quickstart/install/) for the\nsystem requirements and further information.\n\nIf upgrading from Appium 1, make sure Appium 1 is fully uninstalled (`npm uninstall -g appium`).\nUnexpected errors might appear if this has not been done.\n\n```bash\nnpm i -g appium\n```\n\nNote that this will only install the core Appium server, which cannot automate anything on its own.\nPlease install [drivers](#drivers) for your target platforms in order to automate them.\n\n## Drivers\n\nAppium supports app automation across a variety of platforms, like iOS, Android, macOS, Windows,\nand more. Each platform is supported by one or more \"drivers\", which know how to automate that\nparticular platform. You can find a full list of officially-supported and third-party drivers in\n[Appium Ecosystem's Drivers page](http://appium.io/docs/en/latest/ecosystem/drivers/).\n\nDriver management is done using [Appium's Extension command-line interface](http://appium.io/docs/en/latest/cli/extensions/):\n\n```bash\n# Install an official driver from npm (see documentation for a list of such drivers)\nappium driver install <driver-name>\n# Install any driver from npm\nappium driver install --source=npm <driver-name>\n# See documentation for installation from other sources\n\n# List already installed drivers\nappium driver list --installed\n# Update a driver (it must be already installed)\n# This will NOT update the major version, in order to prevent breaking changes\nappium driver update <driver-name>\n# Update a driver to the most recent version (may include breaking changes)\nappium driver update <driver-name> --unsafe\n# Uninstall a driver (it won't last forever, will it?)\nappium driver uninstall <driver-name>\n```\n\n## Clients\n\nClient libraries enable writing Appium tests in different programming languages. There are\nofficially-supported clients for Java, Python, Ruby, and .NET C#, as well as third-party clients\nfor other languages. You can find a full list of clients in\n[Appium Ecosystem's Clients page](http://appium.io/docs/en/latest/ecosystem/clients/).","metadata":{"headerPath":"## Installation","sectionCount":3,"filename":"README.md","relativePath":"appium/README.md"}},{"pageContent":"## Plugins\n\nPlugins allow you to extend server functionality without changing the server code. The main\ndifference between drivers and plugins is that the latter must be explicitly enabled on\nAppium server startup (all installed drivers are enabled by default):\n\n```bash\nappium --use-plugins=<plugin-name>\n```\n\nYou can find a full list of officially-supported and third-party plugins in\n[Appium Ecosystem's Plugins page](http://appium.io/docs/en/latest/ecosystem/plugins/).\n\nSimilarly to drivers, plugin management is also done using\n[Appium's Extension command-line interface](http://appium.io/docs/en/latest/cli/extensions/):\n\n```bash\n# Install an official plugin from npm (see documentation for a list of such plugins)\nappium plugin install <plugin-name>\n# Install any plugin from npm\nappium plugin install --source=npm <plugin-name>\n# See documentation for installation from other sources\n\n# List already installed plugins\nappium plugin list --installed\n# Update a plugin (it must be already installed)\n# This will NOT update the major version, in order to prevent breaking changes\nappium plugin update <plugin-name>\n# Update a plugin to the most recent version (may include breaking changes)\nappium plugin update <plugin-name> --unsafe\n# Uninstall a plugin\nappium plugin uninstall <plugin-name>\n```\n\n## Server Command Line Interface\n\nIn order to start sending commands to the Appium server, it must be running on the URL and port\nwhere your client library expects it to listen. [Appium's command-line interface](http://appium.io/docs/en/latest/cli/server/)\nis used to launch and configure the server:\n\n```bash\n# Start the server on the default host (0.0.0.0) and port (4723)\nappium server\n# You can also omit the 'server' subcommand\nappium\n# Start the server on the given host, port and use a custom base path prefix (the default prefix is '/')\nappium --address 127.0.0.1 --port 9000 --base-path /wd/hub\n```\n\nAppium supports execution of parallel server processes, as well as parallel driver sessions within a\nsingle server process. Refer the corresponding driver documentations regarding which mode is optimal\nfor the particular driver or whether it supports parallel sessions.","metadata":{"headerPath":"## Plugins","sectionCount":2,"filename":"README.md","relativePath":"appium/README.md"}},{"pageContent":"## Why Appium?\n\n1. You usually don't have to recompile your app or modify it in any way, due to the use of standard\n automation APIs on all platforms.\n2. You can write tests with your favorite dev tools using any WebDriver-compatible language such as\n Java, Python, Ruby and C#. There are also third party client implementations for other languages.\n3. You can use any testing framework.\n4. Some drivers like `xcuitest` and `uiautomator2` have built-in mobile web and hybrid app support.\n Within the same script, you can switch seamlessly between native app automation and webview\n automation, all using the WebDriver model that's already the standard for web automation.\n5. You can run your automated tests locally and in a cloud. There are multiple cloud providers that\n support various Appium drivers (mostly targeting iOS and Android mobile automation).\n6. [Appium Inspector](https://github.com/appium/appium-inspector) can be used to visually inspect\n the page source of applications across different platforms, facilitating easier test development.\n\nInvesting in the [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means you\nare betting on a single, free, and open protocol for testing that has become a web standard. Don't\nlock yourself into a proprietary stack.\n\nFor example, if you use Apple's XCUITest library without Appium, you can only write tests using\nObj-C/Swift, and you can only run tests through Xcode. Similarly, with Google's UiAutomator or\nEspresso, you can only write tests in Java/Kotlin. Appium opens up the possibility of true\ncross-platform native app automation, for mobile and beyond!\n\nIf you are looking for a more comprehensive description of what this is all about, please read our\ndocumentation on [How Does Appium Work?](https://appium.io/docs/en/latest/intro/appium/).\n\n## Sponsors\n\nAppium has a [Sponsorship Program](GOVERNANCE.md#sponsorship)! If you or your company uses Appium\nand wants to give back financially to the project, we use these funds to [encourage development and\ncontributions](GOVERNANCE.md#compensation-scheme), as well as support other open source projects we\nrely on. [Become a sponsor](https://opencollective.com/appium) via our OpenCollective page.","metadata":{"headerPath":"## Why Appium?","sectionCount":2,"filename":"README.md","relativePath":"appium/README.md"}},{"pageContent":"## Sponsors > ### Development and Strategic Partners\n\nAppium is incredibly grateful to our Development and Strategic Partners for their sustained\ncontribution of project development and leadership!\n\n<p align=\"center\">\n <a href=\"https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium\">\n <picture>\n <source srcset=\"packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-dark.png\" media=\"(prefers-color-scheme: dark)\"/>\n <source srcset=\"packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-light.png\" media=\"(prefers-color-scheme: light)\"/>\n <img src=\"packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-dark.png\" width=\"300\" alt=\"Browserstack\"/>\n </picture>\n </a>\n</p>\n\n<p align=\"center\">\n <a href=\"https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage\">\n <picture>\n <source srcset=\"packages/appium/docs/overrides/assets/images/sponsor-logo-lambdatest-dark.png\" media=\"(prefers-color-scheme: dark)\"/>\n <source srcset=\"packages/appium/docs/overrides/assets/images/sponsor-logo-lambdatest-light.png\" media=\"(prefers-color-scheme: light)\"/>\n <img src=\"packages/appium/docs/overrides/assets/images/sponsor-logo-lambdatest-dark.png\" width=\"300\" alt=\"LambdaTest\"/>\n </picture>\n </a>\n</p>\n\n## Sponsors > ### Other Sponsors\n\nA full list of sponsors is available at our [Sponsors page](https://appium.io/docs/en/latest/sponsors/).\n\n## License\n\n[Apache-2.0](./LICENSE)\n\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)\n\n`@appium/logger` package is under [ISC](./packages/logger/LICENSE) License.","metadata":{"headerPath":"## Sponsors > ### Development and Strategic Partners","sectionCount":3,"filename":"README.md","relativePath":"appium/README.md"}},{"pageContent":"# Roadmap\n\nThis is not a traditional roadmap. We don't have a typical product team with a typical product\nmanager. The fact that the items below exist on a roadmap is no indication that we will ever have\nthe opportunity to work on them. Instead this is more like a wishlist of outcomes that the project\nthinks would be valuable. If and when we get additional contributions of development work, this is\na set of items that would be great for someone to work on! Ideally, interested devs would find\nsomething on this list and own it from start to finish! Let anyone on the project know if you're\ninterested and we can help get you going.\n\n# Roadmap > ### Core projects\n\n- **WebDriver BiDi support in the Appium server**: the WebDriver BiDi spec is underway, which details a different method for communicating with drivers. We should implement handling for these methods in our server so that Appium drivers can take advantage of the BiDi spec without additional work on their part.\n- **Redevelop automatically generated command docs**: due to changing TypeDoc support and the departure of one of our team, we were forced to remove our TypeDoc-based automatic docs generation tool. It would be nice to bring this back in a more maintainable form!\n\n# Roadmap > ### Driver/platform-specific projects\n\n- **Better maintenance for our Android drivers**: we're looking for Android specialists to help maintain our Android drivers (UiAutomator2 and Espresso)\n- **Better maintenance for our iOS driver**: we're looking for iOS specialists to help maintain our XCUITest driver\n- **Better maintenance for [appium-ios-device](https://github.com/appium/appium-ios-device)**: this project is using outdated approaches and libraries. If it could be improved it would have a big impact on the performance of the XCUITest driver\n\n# Roadmap > ### Client library projects\n\n- **Selenium compatibility client updates**: we'd like to rearchitect our flagship Appium clients to extend rather than wrap Selenium clients, reducing the overall surface area of the Appium clients and making them work more closely with existing Selenium client functionality.","metadata":{"headerPath":"# Roadmap","sectionCount":4,"filename":"ROADMAP.md","relativePath":"appium/ROADMAP.md"}},{"pageContent":"# Roadmap > ### Appium Inspector projects\n\n- **Full support for web inspection**: currently the Appium Inspector has poor to no support for inspecing web pages (either mobile browsers or web content embedded in webviews). It's a common requirement to inspect web elements as part of writing Appium tests, and at the present time users are required to leave the Inspector and open up a browser's devtools.\n- **Record/Playback**: we have a basic record-to-code feature already. It would be nice to be able to save recorded steps and play them back with a little player/editor.\n- **Support for more platforms**: currently there is a fair bit of specialized handling for iOS and Android in the Appium inspector. Other platforms either work poorly or not at all with the Inspector. It would be great to establish a way for drivers to report all the information about how they work to the Inspector, so it can support any platform without needing special-cased code for it.\n- **Locator analysis and comparison**: it would be nice for users to get more information about the relative suitability of using different locators to find elements, as poor locator performance is a leading cause of Appium test instability.\n- **Dark theme**: for true hackers!\n- **Export/import of saved gestures**: it's currently not possible to port your saved gestures to other instances of the Inspector (i.e., to share with team members).\n- **Bulk export/import saved sessions**: would be nice to take your sessions and capabilities with you or to share with colleagues.","metadata":{"headerPath":"# Roadmap > ### Appium Inspector projects","sectionCount":1,"filename":"ROADMAP.md","relativePath":"appium/ROADMAP.md"}},{"pageContent":"# Sponsors & Backers\n\nPlease check [Sponsors & Backers](https://appium.io/docs/en/latest/sponsors/)","metadata":{"headerPath":"# Sponsors & Backers","sectionCount":1,"filename":"SPONSORS.md","relativePath":"appium/SPONSORS.md"}},{"pageContent":"# Docs moved\n\nThe old Appium 1.x docs used to be in this directory. Now, they are available only on the [1.x\nbranch](https://github.com/appium/appium/tree/1.x/docs).\n\nCurrent Appium docs are located in [packages/appium/docs](../packages/appium/docs) in this repo.","metadata":{"headerPath":"# Docs moved","sectionCount":1,"filename":"README.md","relativePath":"appium/docs/README.md"}},{"pageContent":"This documentation is a note for the opencollective payout.\n\n1. Select `Submit expense`\n\n<img width=\"200\" alt=\"Screenshot 2024-09-17 at 11 04 32 PM\" src=\"https://github.com/user-attachments/assets/5d598a46-8aa3-41e0-aadc-ce3f34b10f6b\">\n\n2. Select `Appium` in `Who is paying`\n3. Select `Invite someone` and fill in a user name to pay payouts for\n4. Select `Invoice` for `Select the type of expense`\n5. Check the `I have read and understood the instructions and conditions` agreement\n6. Select `No, generate an invoice for me`\n - Keep blank for the `Additional invoice information (optional)`\n8. Fill in the description in the `Item Description`, date and amount for `Expense Items`\n - for TCs:\n - `<year-month> contribution as a TC https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee and maintaining Appium project itself (development, review etc)`\n - i.e. `2024-07 contribution as a TC https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee and maintaining Appium project itself (development, review etc)`\n - for individuals\n - `PR contribution: <PRs>` for PRs. `Community contribution in Q&A forum at https://discuss.appium.io/` for appium forums\n - E.g.\n - `PR contribution: https://github.com/appium/dotnet-client/pull/810, https://github.com/appium/dotnet-client/pull/808`\n - `PR contribution: https://github.com/appium/java-client/pull/2206, https://github.com/appium/java-client/pull/2203 and a few PRs`\n - `Community contribution in Q&A forum at https://discuss.appium.io/`\n - Translations\n - e.g.\n - `Translation contributions for https://crowdin.com/project/appium-documentation`\n - For Date\n - today\n - For Amount\n - Put the payment amount in USD\n9. Fill in title in `Title` in `Additional details`\n - Expense title: `<year-month> contribution payout`\n - e.g. `2024-07 contribution payout`\n10. Submit expense\n11. Update the expense url in our payout sheet\n12. Approve each expense after getting a response for each expense","metadata":{"headerPath":"","sectionCount":1,"filename":"payout.md","relativePath":"appium/docs/payout.md"}},{"pageContent":"<p align=\"center\">\n <a href=\"https://appium.io/\">\n <img alt=\"Appium\" src=\"https://raw.githubusercontent.com/appium/appium/master/packages/appium/docs/overrides/assets/images/appium-logo-horiz.png\" width=\"500\">\n </a>\n</p>\n<p align=\"center\">\n Cross-platform test automation for native, hybrid, mobile web and desktop apps.\n</p>\n\n<div align=\"center\">\n\n[![NPM version](https://badge.fury.io/js/appium.svg)](https://npmjs.org/package/appium)\n[![Monthly Downloads](https://img.shields.io/npm/dm/appium.svg)](https://npmjs.org/package/appium)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_shield)\n[![StandWithUkraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://github.com/vshymanskyy/StandWithUkraine/)\n[![CeasefireInGaza](https://img.shields.io/badge/Ceasefire_Now-%F0%9F%87%B5%F0%9F%87%B8-red?style=flat)](https://www.unrwa.org/)\n\n</div>\n\n***\n\n<p align=\"center\"><b>\n <a href=\"https://appium.io\">Documentation</a> |\n <a href=\"https://appium.io/docs/en/latest/intro/\">Get Started</a> |\n <a href=\"https://appium.io/docs/en/latest/ecosystem/\">Ecosystem</a> |\n <a href=\"https://github.com/appium/appium/blob/master/packages/appium/CHANGELOG.md\">Changelog</a> |\n <a href=\"https://appium.io/docs/en/latest/contributing/\">Contributing Guide</a> |\n <a href=\"https://discuss.appium.io\">Discussion Forum</a>\n</b></p>\n\n***\n\nAppium is an open-source automation framework that provides\n[WebDriver](https://www.w3.org/TR/webdriver/)-based automation possibilities for a wide range of\ndifferent mobile, desktop and IoT platforms. Appium is modular and extensible, and supports multiple\nprogramming languages, which means there is an entire ecosystem of related software:\n* [__Drivers__](#drivers) add support for automating specific platforms\n* [__Clients__](#clients) allow writing Appium tests in your programming language of choice\n* [__Plugins__](#plugins) allow to further extend Appium functionality\n\n## Upgrading From Older Versions\n\nThe Appium team only provides support for the most recent version of Appium. If you wish to upgrade from\nan older major Appium version, please refer to the migration guides:\n\n* [Appium v2 to v3](https://appium.io/docs/en/latest/guides/migrating-2-to-3/)\n* [Appium v1 to v2](https://appium.io/docs/en/latest/guides/migrating-1-to-2/)","metadata":{"headerPath":"","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/appium/README.md"}},{"pageContent":"## Installation\n\nAppium can be installed using `npm` (other package managers are not currently supported). Please\ncheck the [installation docs](http://appium.io/docs/en/latest/quickstart/install/) for the\nsystem requirements and further information.\n\nIf upgrading from Appium 1, make sure Appium 1 is fully uninstalled (`npm uninstall -g appium`).\nUnexpected errors might appear if this has not been done.\n\n```bash\nnpm i -g appium\n```\n\nNote that this will only install the core Appium server, which cannot automate anything on its own.\nPlease install [drivers](#drivers) for your target platforms in order to automate them.\n\n## Drivers\n\nAppium supports app automation across a variety of platforms, like iOS, Android, macOS, Windows,\nand more. Each platform is supported by one or more \"drivers\", which know how to automate that\nparticular platform. You can find a full list of officially-supported and third-party drivers in\n[Appium Ecosystem's Drivers page](http://appium.io/docs/en/latest/ecosystem/drivers/).\n\nDriver management is done using [Appium's Extension command-line interface](http://appium.io/docs/en/latest/cli/extensions/):\n\n```bash\n# Install an official driver from npm (see documentation for a list of such drivers)\nappium driver install <driver-name>\n# Install any driver from npm\nappium driver install --source=npm <driver-name>\n# See documentation for installation from other sources\n\n# List already installed drivers\nappium driver list --installed\n# Update a driver (it must be already installed)\n# This will NOT update the major version, in order to prevent breaking changes\nappium driver update <driver-name>\n# Update a driver to the most recent version (may include breaking changes)\nappium driver update <driver-name> --unsafe\n# Uninstall a driver (it won't last forever, will it?)\nappium driver uninstall <driver-name>\n```\n\n## Clients\n\nClient libraries enable writing Appium tests in different programming languages. There are\nofficially-supported clients for Java, Python, Ruby, and .NET C#, as well as third-party clients\nfor other languages. You can find a full list of clients in\n[Appium Ecosystem's Clients page](http://appium.io/docs/en/latest/ecosystem/clients/).","metadata":{"headerPath":"## Installation","sectionCount":3,"filename":"README.md","relativePath":"appium/packages/appium/README.md"}},{"pageContent":"## Plugins\n\nPlugins allow you to extend server functionality without changing the server code. The main\ndifference between drivers and plugins is that the latter must be explicitly enabled on\nAppium server startup (all installed drivers are enabled by default):\n\n```bash\nappium --use-plugins=<plugin-name>\n```\n\nYou can find a full list of officially-supported and third-party plugins in\n[Appium Ecosystem's Plugins page](http://appium.io/docs/en/latest/ecosystem/plugins/).\n\nSimilarly to drivers, plugin management is also done using\n[Appium's Extension command-line interface](http://appium.io/docs/en/latest/cli/extensions/):\n\n```bash\n# Install an official plugin from npm (see documentation for a list of such plugins)\nappium plugin install <plugin-name>\n# Install any plugin from npm\nappium plugin install --source=npm <plugin-name>\n# See documentation for installation from other sources\n\n# List already installed plugins\nappium plugin list --installed\n# Update a plugin (it must be already installed)\n# This will NOT update the major version, in order to prevent breaking changes\nappium plugin update <plugin-name>\n# Update a plugin to the most recent version (may include breaking changes)\nappium plugin update <plugin-name> --unsafe\n# Uninstall a plugin\nappium plugin uninstall <plugin-name>\n```\n\n## Server Command Line Interface\n\nIn order to start sending commands to the Appium server, it must be running on the URL and port\nwhere your client library expects it to listen. [Appium's command-line interface](http://appium.io/docs/en/latest/cli/server/)\nis used to launch and configure the server:\n\n```bash\n# Start the server on the default host (0.0.0.0) and port (4723)\nappium server\n# You can also omit the 'server' subcommand\nappium\n# Start the server on the given host, port and use a custom base path prefix (the default prefix is '/')\nappium --address 127.0.0.1 --port 9000 --base-path /wd/hub\n```\n\nAppium supports execution of parallel server processes, as well as parallel driver sessions within a\nsingle server process. Refer the corresponding driver documentations regarding which mode is optimal\nfor the particular driver or whether it supports parallel sessions.","metadata":{"headerPath":"## Plugins","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/appium/README.md"}},{"pageContent":"## Why Appium?\n\n1. You usually don't have to recompile your app or modify it in any way, due to the use of standard\n automation APIs on all platforms.\n2. You can write tests with your favorite dev tools using any WebDriver-compatible language such as\n Java, Python, Ruby and C#. There are also third party client implementations for other languages.\n3. You can use any testing framework.\n4. Some drivers like `xcuitest` and `uiautomator2` have built-in mobile web and hybrid app support.\n Within the same script, you can switch seamlessly between native app automation and webview\n automation, all using the WebDriver model that's already the standard for web automation.\n5. You can run your automated tests locally and in a cloud. There are multiple cloud providers that\n support various Appium drivers (mostly targeting iOS and Android mobile automation).\n6. [Appium Inspector](https://github.com/appium/appium-inspector) can be used to visually inspect\n the page source of applications across different platforms, facilitating easier test development.\n\nInvesting in the [WebDriver](https://w3c.github.io/webdriver/webdriver-spec.html) protocol means you\nare betting on a single, free, and open protocol for testing that has become a web standard. Don't\nlock yourself into a proprietary stack.\n\nFor example, if you use Apple's XCUITest library without Appium, you can only write tests using\nObj-C/Swift, and you can only run tests through Xcode. Similarly, with Google's UiAutomator or\nEspresso, you can only write tests in Java/Kotlin. Appium opens up the possibility of true\ncross-platform native app automation, for mobile and beyond!\n\nIf you are looking for a more comprehensive description of what this is all about, please read our\ndocumentation on [How Does Appium Work?](https://appium.io/docs/en/latest/intro/appium/).\n\n## Sponsors\n\nAppium has a [Sponsorship Program](GOVERNANCE.md#sponsorship)! If you or your company uses Appium\nand wants to give back financially to the project, we use these funds to [encourage development and\ncontributions](GOVERNANCE.md#compensation-scheme), as well as support other open source projects we\nrely on. [Become a sponsor](https://opencollective.com/appium) via our OpenCollective page.","metadata":{"headerPath":"## Why Appium?","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/appium/README.md"}},{"pageContent":"## Sponsors > ### Development and Strategic Partners\n\nAppium is incredibly grateful to our Development and Strategic Partners for their sustained\ncontribution of project development and leadership!\n\n<p align=\"center\">\n <a href=\"https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium\">\n <picture>\n <source srcset=\"packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-dark.png\" media=\"(prefers-color-scheme: dark)\"/>\n <source srcset=\"packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-light.png\" media=\"(prefers-color-scheme: light)\"/>\n <img src=\"packages/appium/docs/overrides/assets/images/sponsor-logo-browserstack-dark.png\" width=\"300\" alt=\"Browserstack\"/>\n </picture>\n </a>\n</p>\n\n<p align=\"center\">\n <a href=\"https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage\">\n <picture>\n <source srcset=\"packages/appium/docs/overrides/assets/images/sponsor-logo-lambdatest-dark.png\" media=\"(prefers-color-scheme: dark)\"/>\n <source srcset=\"packages/appium/docs/overrides/assets/images/sponsor-logo-lambdatest-light.png\" media=\"(prefers-color-scheme: light)\"/>\n <img src=\"packages/appium/docs/overrides/assets/images/sponsor-logo-lambdatest-dark.png\" width=\"300\" alt=\"LambdaTest\"/>\n </picture>\n </a>\n</p>\n\n## Sponsors > ### Other Sponsors\n\nA full list of sponsors is available at our [Sponsors page](https://appium.io/docs/en/latest/sponsors/).\n\n## License\n\n[Apache-2.0](./LICENSE)\n\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fappium%2Fappium?ref=badge_large)\n\n`@appium/logger` package is under [ISC](./packages/logger/LICENSE) License.","metadata":{"headerPath":"## Sponsors > ### Development and Strategic Partners","sectionCount":3,"filename":"README.md","relativePath":"appium/packages/appium/README.md"}},{"pageContent":"---\nhide:\n - navigation\n\ntitle: Contributing to Appium\n---\n\nThe Appium project would not exist without the many contributions of code, documentation,\nmaintenance, and support from companies and volunteers. As such, we welcome contributions!\n\nThere are a lot of different ways to help the project - see below for everything you can do and the\nprocesses to follow for each contribution method. Note that no matter how you contribute, your\nparticipation is governed by our [Code of Conduct](https://github.com/appium/appium/blob/master/CONDUCT.md).\n\n## Join the Discussion Forum\n\nYou don't need to know the internals of Appium to be able to contribute! If you have experience with\nusing Appium and feel like sharing your knowledge with others, consider helping out users on the\nAppium forums at [discuss.appium.io](https://discuss.appium.io/). Hop on over and see if there are\nany questions that you can answer.\n\n## Report Bugs or Feature Requests\n\nIf you've encountered a bug, or have a cool feature in mind that you think Appium should support,\nmake sure to let us know at our [GitHub issue tracker](https://github.com/appium/appium/issues).\nPlease use the appropriate issue form template when creating your issue.\n\n## Triage Issues\n\nIn addition to creating issues, you can also help us investigate already reported issues. All you\nneed is enough familiarity with Appium to try and reproduce bugs.\n\nYou can get started by checking our [GitHub issue tracker](https://github.com/appium/appium/issues)\nfor issues with labels such as `Needs Triage` or `Needs Info`, and leaving relevant comments:\n\n- If the issue is a duplicate, drop a link to the original issue\n- If the user has not provided enough information (such as Appium logs), ask them for more details\n- If you can reproduce the problem on your own environment, provide all the information that you think\n would help us track down the cause of the issue\n\nFor further information on triaging Appium issues (for any Appium project repository), please contact\nany member of the [Technical Committee](https://github.com/appium/appium/blob/master/GOVERNANCE.md#the-technical-committee).","metadata":{"headerPath":"","sectionCount":4,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/contributing/index.md"}},{"pageContent":"## Contribute Code\n\nWe are always open to pull requests for improving the Appium code or documentation!\n\n!!! info\n\n Developer information may not be kept up to date as frequently as user-facing information, or\n it may be most relevant in its current form on the online repository, not in this published\n version. Make sure to check the repo or discuss with maintainers. We would be glad to help\n new contributors get started!\n\nStart by cloning the repository (we recommend [forking](https://github.com/appium/appium/fork)\nit first):\n```sh\ngit clone https://github.com/appium/appium.git\ncd appium\n```\n\n!!! info\n\n If you are VS Code user, you can easily check out the project using [Runme](https://runme.dev/api/runme?repository=https%3A%2F%2Fgithub.com%2Fappium%2Fappium.git&fileToOpen=packages%2Fappium%2Fdocs%2Fen%2Fcontributing%2Findex.md).\n\nInstall dependencies:\n```sh\nnpm install\n```\n\nFrom here on there are several things you can do.\n\nBuild the project:\n```sh\nnpm run build\n```\n\nBuild the project and watch for changes:\n```sh\nnpm run dev\n```\n\nStart the locally built Appium server:\n```sh\nnpm start\n```\n\nRun various tests:\n```sh\nnpm run lint\nnpm run test:unit\nnpm run test:types\nnpm run test:smoke\nnpm run test:e2e\nnpm run test:quick # unit and types\nnpm run test:slow # everything\n```\n\nYou can also run tests for specific workspaces, e.g.:\n\n```sh\nexport APPIUM_WORKSPACE=@appium/base-driver\nnpm run test:unit -w $APPIUM_WORKSPACE\n```\n\n## Contribute Code > ### Documentation\n\nThe documentation for this project is [available in the project repository itself](https://github.com/appium/appium/tree/master/packages/appium/docs).\nIt is contained in Markdown files, which are built by our documentation system in the\n`@appium/docutils` module. This module is based on [MkDocs](https://www.mkdocs.org/) and therefore\nrequires [Python](https://www.python.org/) to be installed on your system.\n\nInstall Python dependencies:\n```sh\nnpm run install-docs-deps\n```\n\nAfter making your changes, you can run the documentation server in dev mode:\n```sh\nnpm run dev:docs\n```\n\nYou can then view the documentation at `http://127.0.0.1:8000/docs/en`.","metadata":{"headerPath":"## Contribute Code","sectionCount":2,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/contributing/index.md"}},{"pageContent":"## Translating Appium Documentation\n\nThe process of Appium documents localization into languages other than English is automated and is done via\nthe [Crowdin Translations Management System](https://crowdin.com). Do not edit any translated documents\ndirectly in the GitHub Appium repository as they are going to be replaced with ones exported from Crowdin\nduring an upcoming sync.\n\n## Translating Appium Documentation > ### Where To Start\n\nIf you would like to contribute to the translation of Appium documents into your language then simply join\nthe translators group for the [Appium Documentation](https://crowdin.com/project/appium-documentation)\nCrowdin project, and start translating documents there. If you see that your language is missing from\nthe list of available Crowdin languages then simply let us know by creating an\n[issue](https://github.com/appium/appium/issues).\n\n## Translating Appium Documentation > ### Source Language Updates\n\nChanges in documents are synchronized to Crowdin automatically via the `Update Crowdin English Docs` GitHub action.\nThis action is triggered automatically as soon as there are any changes under `packages/appium/docs/en/**.md`\nor `packages/appium/docs/mkdocs-en.yml`.\n\n## Translating Appium Documentation > ### Fetching Translated Documents\n\nIn order to fetch translated files from Crowdin to the GitHub repository it is necessary to trigger\nthe `Sync Crowdin Docs Translations` action. This action should also automatically create a PR with\ncorresponding translated resources included.","metadata":{"headerPath":"## Translating Appium Documentation","sectionCount":4,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/contributing/index.md"}},{"pageContent":"---\ntitle: Building Documentation\n---\n\nOnce you've [built a driver](./build-drivers.md) or [built a plugin](./build-plugins.md) for Appium,\nyou will hopefully want to document how that extension works for your users. The most basic way of\ndoing this is to write up a quick `README.md` and keep it in the root of your project's repository.\nHowever, this can involve a lot of effort.\n\nThe Appium project has built tools to help with this, and we've packaged up these tools so our\necosystem developers building drivers and plugins can _also_ use them. The best way to get going\nwith these tools is probably to look at an existing Appium driver repo to see how it's done, for\nexample the [XCUITest driver repo](https://github.com/appium/appium-xcuitest-driver). But this guide\nwill outline the basic approach.\n\n### Conceptual architecture\n\nAppium settled on [MkDocs](https://www.mkdocs.org/) as a Markdown-based documentation site\ngenerator. It uses a Python toolchain (and not Node.js), but it turned out to be the best option\nfor our purposes. You can adjust this, but by default Appium's utilities also assume that you'll be\nusing the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) theme/extension for\nMkDocs.\n\nIn order to make different versions of your docs available (one for each minor release of your\nextension, typically), we also bundle [Mike](https://github.com/jimporter/mike).\n\nFrom here, building a basic docs site is as easy as collecting your Markdown files together and\ndefining how you want them to be organized.\n\n### Prerequisites\n\nTo take advantage of Appium's documentation utilities, you'll need to install:\n\n- [Python v3+](https://www.python.org/downloads/)\n- [pip](https://pip.pypa.io/en/stable/installation/) (this may be installed automatically with Python)\n- The `@appium/docutils` package:\n\n ```bash\n npm install --save-dev @appium/docutils\n ```\n\n### Initializing an Extension for Building Docs\n\nTo prepare your extension for generating documentation, run the following command:\n\n```bash\nnpx appium-docs init\n```\n\nThis will:\n\n1. Create a `tsconfig.json` if one does not already exist. This is necessary even if your extension\nis not written in TypeScript.\n2. Create a `mkdocs.yml` with the necessary configuration for MkDocs.","metadata":{"headerPath":"","sectionCount":4,"filename":"build-docs.md","relativePath":"appium/packages/appium/docs/en/developing/build-docs.md"}},{"pageContent":"### Documenting Your Extension\n\nAt this point, you can begin documenting your extension. By default, MkDocs will look for Markdown\nfiles in the `docs` directory. You can therefore create your Markdown documentation files, place\nthem in `docs`, and add links to these files in `mkdocs.yml`.\n\nRefer to the [MkDocs documentation](https://www.mkdocs.org/user-guide/writing-your-docs/) for\ninformation on how to organize and structure your documentation.\n\n### Building the Docs\n\nAt this point, you can use the `appium-docs` CLI tool. Run this tool with no arguments to get the\nfull help output and see all the available subcommands and parameters. Here are a few usage\nexamples:\n\n```bash\n# Generate reference and build the mkdocs site into the site dir\nnpx appium-docs build\n\n# Same as build, but host the docs on a local dev server\n# and watch for changes and rebuild when files change\nnpx appium-docs build --serve\n\n# Build the docs and deploy them with mike versioning to the docs-site branch\n# using the included commit message.\n# This is particularly useful for pushing content to a GitHub pages branch!\nnpx appium-docs build \\\n --deploy \\\n -b docs-site \\\n -m 'docs: auto-build docs for appium-xcuitest-driver@%s'\n```","metadata":{"headerPath":"### Documenting Your Extension","sectionCount":2,"filename":"build-docs.md","relativePath":"appium/packages/appium/docs/en/developing/build-docs.md"}},{"pageContent":"---\ntitle: Building Doctor Checks\n---\n\nThe idea of Appium Doctor is to assist users with driver or plugin preconditions setup. Sometimes such\npreconditions might be quite complicated and require non-trivial technical knowledge. Doctor checks,\nwhich are vanilla Node.js class instances written by extension authors, simplify\nthe setup process by automating diagnostics and possible fixes for the found issues. These checks\nmight also be interactive to ensure better usage experience.\n\nThis tutorial is supposed to be used by plugin or driver authors that would like to help their users\nto deal with complicated setup or configuration steps.\n\n## Adding Doctor Checks\n\n## Adding Doctor Checks > ### Typing Requirements\n\nThe term `Doctor Check` literally describes a single javascript class instance that implements the\n[IDoctorCheck interface](https://github.com/appium/appium/blob/master/packages/types/lib/doctor.ts).\nThe interface defines the following methods and properties:\n\n- `diagnose(): Promise<DoctorCheckResult>`: Contains the code to diagnose a possible issue\n- `fix(): Promise<string|null>`: Either fixes the actual problem if `hasAutofix()` returns true or\n returns a string description for possible manual fixes. If this method throws an exception named\n `FixSkippedError` and `hasAutofix()` returns true then the result of the method invocation\n is going to be ignored.\n- `hasAutofix(): boolean`: Whether calling `fix()` would resolve the found issue\n- `isOptional(): boolean`: Whether the found issue can be ignored and is not a showstopper\n- `log: AppiumLogger`: May be used for logging. This property may be assigned\n by the instance itself or by the Appium server if it is left unassigned.\n\nThe `DoctorCheckResult` object returned by the `diagnose()` method must contain the following properties:\n\n- `ok: boolean`: Whether the diagnosis found no issues\n- `optional: boolean`: Whether the diagnosed issue is safe to ignore\n- `message: string`: The text message describing the diagnostic result","metadata":{"headerPath":"","sectionCount":3,"filename":"build-doctor-checks.md","relativePath":"appium/packages/appium/docs/en/developing/build-doctor-checks.md"}},{"pageContent":"## Adding Doctor Checks > ### Manifest Requirements\n\nA single extension may export multiple Doctor checks to Appium. In order for these checks to be properly\npicked up by the server CLI after the corresponding extension is installed they might be listed in the\npackage .json manifest under the `appium.doctor.checks` section similar to the definition below:\n\n```json\n // ...\n \"appium\": {\n \"driverName\": \"fake\",\n \"automationName\": \"Fake\",\n \"platformNames\": [\n \"Fake\"\n ],\n \"mainClass\": \"FakeDriver\",\n \"schema\": \"./build/lib/fake-driver-schema.js\",\n \"scripts\": {\n \"fake-error\": \"./build/lib/scripts/fake-error.js\",\n \"fake-success\": \"./build/lib/scripts/fake-success.js\",\n \"fake-stdin\": \"./build/lib/scripts/fake-stdin.js\"\n },\n \"doctor\": {\n \"checks\": [\n \"./doctor/fake1.js\",\n \"./doctor/fake2.js\"\n // ...\n ]\n }\n },\n // ...\n```\n\nAlso, it makes sense to include the [@appium/types](https://www.npmjs.com/package/@appium/types) import\nto the package dev dependencies.","metadata":{"headerPath":"## Adding Doctor Checks > ### Manifest Requirements","sectionCount":1,"filename":"build-doctor-checks.md","relativePath":"appium/packages/appium/docs/en/developing/build-doctor-checks.md"}},{"pageContent":"## Adding Doctor Checks > ### Implementation Example\n\nThe below example is a \"raw\" Node.JS implementation that does not use any transpilation:\n\n```js\nconst {fs, doctor} = require('@appium/support');\n\n/** @satisfies {import('@appium/types').IDoctorCheck} */\nclass EnvVarAndPathCheck {\n /**\n * @param {string} varName\n */\n constructor(varName) {\n this.varName = varName;\n }\n\n async diagnose() {\n const varValue = process.env[this.varName];\n if (typeof varValue === 'undefined') {\n return doctor.nok(`${this.varName} environment variable is NOT set!`);\n }\n\n if (await fs.exists(varValue)) {\n return doctor.ok(`${this.varName} is set to: ${varValue}`);\n }\n\n return doctor.nok(`${this.varName} is set to '${varValue}' but this is NOT a valid path!`);\n }\n\n async fix() {\n return (\n `Make sure the environment variable ${this.varName} is properly configured for the Appium server process`\n );\n }\n\n hasAutofix() {\n return false;\n }\n\n isOptional() {\n return false;\n }\n}\n\nconst androidHomeCheck = new EnvVarAndPathCheck('ANDROID_HOME');\n\nmodule.exports = {androidHomeCheck};\n\n/**\n * @typedef {import('@appium/types').DoctorCheckResult} CheckResult\n */\n```\n\nThis file could be saved as `doctor/android-home-check.js` and then added to the package.json manifest\nas\n\n```json\n // ...\n \"appium\": {\n // ...\n \"doctor\": {\n \"checks\": [\n \"./doctor/android-home-check.js\",\n ]\n }\n // ...\n },\n // ...\n```","metadata":{"headerPath":"## Adding Doctor Checks > ### Implementation Example","sectionCount":1,"filename":"build-doctor-checks.md","relativePath":"appium/packages/appium/docs/en/developing/build-doctor-checks.md"}},{"pageContent":"---\ntitle: Building Drivers\n---\n\nAppium wants to make it easy for anyone to develop their own automation drivers as part of the\nAppium ecosystem. This guide will explain what's involved and how you can accomplish various driver\ndevelopment tasks using the tools Appium provides. This guide assumes you (1) are a competent user of\nAppium, (2) are a competent Node.js developer, and (3) that you have read and understood the\n[Driver Intro](../intro/drivers.md).\n\nIf that describes you, great! This guide will get you started.\n\n## Before you create your driver\n\nBefore you get to work implementing your driver, it's important to have a few things sorted out.\nFor example, you need to know what your driver will do. Which platform is it trying to expose\nWebDriver automation for?\n\nAppium doesn't magically give you the power to automate any platform. All it does is give you a set\nof convenient tools for implementing the WebDriver Protocol. So if you want to create, for example,\na driver for a new app platform, you'll need to know how to automate apps on that platform *without Appium*.\n\nThis usually means that you need to be very familiar with app development for a given platform. And\nit usually means that you will rely on tools or SDKs provided by the platform vendor.\n\nBasically, if you can't answer the question **\"how would I launch, remotely trigger behaviours, and\nread state from an app on this platform?\" then you're not quite ready to write an Appium driver**.\nMake sure you do the research to feel comfortable that there *is* a path forward. Once there is,\ncoding it up and making it available as an Appium driver should be the easy part!\n\n## Other drivers to reference\n\nOne of the greatest things about building an Appium driver is that there are already a number of\nopen source Appium drivers which you can look at for reference. There is\na [fake-driver](https://github.com/appium/appium/tree/master/packages/fake-driver) sample driver which\ndoes basically nothing other than showcase some of the things described in this guide.\n\nAnd of course, all of Appium's official drivers are open source and available in repositories at\nthe project's GitHub organization. So if you ever find yourself asking, \"how does a driver do X?\",\nread the code for these drivers! Also don't be afraid to ask questions of the Appium developers if\nyou get stuck; we're always happy to help make sure the driver development experience is a good\none!","metadata":{"headerPath":"","sectionCount":3,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Basic requirements for Appium drivers\n\nThese are the things your driver *must* do (or be), if you want it to be a valid Appium driver.\n\n## Basic requirements for Appium drivers > ### Node.js package with Appium extension metadata\n\nAll Appium drivers are fundamentally Node.js packages, and therefore must have a valid\n`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in Node.js so it can be loaded by Appium.\n\nYour `package.json` must include `appium` as a `peerDependency`. The requirements for the\ndependency versions should be as loose as possible (unless you happen to know your driver will only\nwork with certain versions of Appium). For Appium 2, for example, this would look something like\n`^2.0.0`, declaring that your driver works with any version of Appium that starts with 2.x.\n\nYour `package.json` must contain an `appium` field, like this (we call this the 'Appium extension\nmetadata'):\n\n```json\n{\n ...,\n \"appium\": {\n \"driverName\": \"fake\",\n \"automationName\": \"Fake\",\n \"platformNames\": [\n \"Fake\"\n ],\n \"mainClass\": \"FakeDriver\"\n },\n ...\n}\n```\n\nThe required subfields are:\n\n* `driverName`: this should be a short name for your driver.\n* `automationName`: this should be the string users will use for their `appium:automationName`\n capability to tell Appium to use *your* driver.\n* `platformNames`: this is an array of one or more platform names considered valid for your driver.\n When a user sends in the `platformName` capability to start a session, it must be included in\n this list for your driver to handle the session. Known platform name strings include: `iOS`,\n `tvOS`, `macOS`, `Windows`, `Android`.\n* `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a\n class which extends Appium's `BaseDriver` (see below).\n\n## Basic requirements for Appium drivers > ### Extend Appium's `BaseDriver` class\n\nUltimately, your driver is much easier to write because most of the hard work of implementing the\nWebDriver protocol and handling certain common logic is taken care of already by Appium. This is\nall encoded up as a class which Appium exports for you to use, called `BaseDriver`. It is exported\nfrom `appium/driver`, so you can use one of these styles to import it and create your *own* class\nthat extends it:\n\n```js\nimport {BaseDriver} from 'appium/driver';\n// or: const {BaseDriver} = require('appium/driver');\n\nexport class MyDriver extends BaseDriver {\n}\n```","metadata":{"headerPath":"## Basic requirements for Appium drivers","sectionCount":3,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Basic requirements for Appium drivers > ### Make your driver available\n\nThat's basically it! With a Node.js package exporting a driver class and with correct Appium\nextension metadata, you've got yourself an Appium driver! Now it doesn't *do* anything, but you can\nload it up in Appium, start and stop sessions with it, etc...\n\nTo make it available to users, you could publish it via NPM. When you do so, your driver will be\ninstallable via the Appium CLI:\n\n```\nappium driver install --source=npm <driver-package-on-npm>\n```\n\nIt's a good idea to test your driver first, of course. One way to see how it works within Appium is\nto install it locally first:\n\n```\nappium driver install --source=local /path/to/your/driver\n```\n\n## Basic requirements for Appium drivers > ### Developing your driver\n\nHow you develop your driver is up to you. It is convenient, however, to run it from within Appium\nwithout having to do lots of publishing and installing. The most straightforward way to do this is\nto include the most recent version of Appium as a `devDependency`, and then also your own driver,\nlike this:\n\n```json\n{\n \"devDependencies\": {\n ...,\n \"appium\": \"^2.0.0\",\n \"your-driver\": \"file:.\",\n ...\n }\n}\n```\n\nNow, you can run Appium locally (`npm exec appium` or `npx appium`), and because your driver is\nlisted as a dependency alongside it, it will be automatically \"installed\" and available. You can\ndesign your e2e tests this way, or if you're writing them in Node.js, you can simply import\nAppium's start server methods to handle starting and stopping the Appium server in Node. (TODO:\nreference an implementation of this in one of the open source drivers when ready).\n\nAnother way to do local development with an existing Appium server install is to simply install\nyour driver locally:\n\n```\nappium driver install --source=local /path/to/your/driver/dev/dir\n```\n\n## Basic requirements for Appium drivers > ### Refreshing your driver during development\n\nWhen the Appium server starts, it loads your driver into memory. Changes to your driver code will\nnot take effect until the next time the Appium server starts. Simply starting a new session is not\nsufficient to cause your driver's code to be reloaded.\n\nHowever, you can set the `APPIUM_RELOAD_EXTENSIONS` environment variable to `1` to request that\nAppium clear its module cache and reload extensions whenever a new session is requested. This may\nobviate the need to restart the server when you make code changes to your driver.","metadata":{"headerPath":"## Basic requirements for Appium drivers > ### Make your driver available","sectionCount":3,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Standard driver implementation ideas\n\nThese are things you will probably find yourself wanting to do when creating a driver.\n\n## Standard driver implementation ideas > ### Set up state in a constructor\n\nIf you define your own constructor, you'll need to call `super` to make sure all the standard state\nis set up correctly:\n\n```js\nconstructor(...args) {\n super(...args);\n // now do your own thing\n}\n```\n\nThe `args` parameter here is the object containing all the CLI args used to start the Appium\nserver.\n\n## Standard driver implementation ideas > ### Define and validate accepted capabilities\n\nYou can define your own capabilities and basic validation for them. Users will always be able to\nsend in capabilities that you don't define, but if they send in capabilities you have explicitly\ndefined, then Appium will validate that they are of the correct type (and will check for the\npresence of required capabilities).\n\nIf you want to turn capability validation off entirely, set `this.shouldValidateCaps` to `false` in\nyour constructor.\n\nTo give Appium your validation constraints, set `this.desiredCapConstraints` to a validation object\nin your constructor. Validation objects can be somewhat complex. Here's an example from the\nUiAutomator2 driver:\n\n```js\n{\n app: {\n presence: true,\n isString: true\n },\n automationName: {\n isString: true\n },\n browserName: {\n isString: true\n },\n launchTimeout: {\n isNumber: true\n },\n}\n```","metadata":{"headerPath":"## Standard driver implementation ideas","sectionCount":3,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Standard driver implementation ideas > ### Start a session and read capabilities\n\nAppium's `BaseDriver` already implements the `createSession` command, so you don't have to. However\nit's very common to need to perform your own startup actions (launching an app, running some\nplatform code, or doing different things based on capabilities you have defined for your driver).\nSo you'll probably end up overriding `createSession`. You can do so by defining the method in your\ndriver:\n\n```js\nasync createSession(jwpCaps, reqCaps, w3cCaps, otherDriverData) {\n const [sessionId, caps] = super.createSession(w3cCaps);\n // do your own stuff here\n return [sessionId, caps];\n}\n```\n\nFor legacy reasons, your function will receive old-style JSON Wire Protocol desired and required\ncaps as the first two arguments. Given that the old protocol isn't supported anymore and clients\nhave all been updated, you can instead only rely on the `w3cCaps` parameter. (For a discussion\nabout what `otherDriverData` is about, see the section below on concurrent drivers).\n\nYou'll want to make sure to call `super.createSession` in order to get the session ID as well as\nthe processed capabilities (note that capabilities are also set on `this.caps`; modifying `caps`\nlocally here would have no effect other than changing what the user sees in the create session\nresponse).\n\nSo that's it! You can fill out the middle section with whatever startup logic your driver requires.\n\n## Standard driver implementation ideas > ### End a session\n\nIf your driver requires any cleanup or shutdown logic, it's best to do it as part of overriding the\nimplementation of `deleteSession`:\n\n```js\nasync deleteSession() {\n // do your own cleanup here\n // don't forget to call super!\n await super.deleteSession();\n}\n```\n\nIt's very important not to throw any errors here if possible so that all parts of session cleanup\ncan succeed!","metadata":{"headerPath":"## Standard driver implementation ideas > ### Start a session and read capabilities","sectionCount":2,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Standard driver implementation ideas > ### Access capabilities and CLI args\n\nYou'll often want to read parameters the user has set for the session, whether as CLI args or as\ncapabilities. The easiest way to do this is to access `this.opts`, which is a merge of all options,\nfrom the CLI or from capabilities. So for example to access the `appium:app` capability, you could\nsimply get the value of `this.opts.app`.\n\nIf you care about knowing whether something was sent in as a CLI arg *or* a capability, you can\naccess the `this.cliArgs` and `this.caps` objects explicitly.\n\nIn all cases, the `appium:` capability prefix will have been stripped away by the time you are\naccessing values here, for convenience.","metadata":{"headerPath":"## Standard driver implementation ideas > ### Access capabilities and CLI args","sectionCount":1,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Standard driver implementation ideas > ### Implement WebDriver classic commands\n\nYou handle WebDriver commands by implementing functions in your driver class. Each member of the\nWebDriver Protocol, plus the various Appium extensions, has a corresponding function that you\nimplement if you want to support that command in your driver. The best way to see which commands\nAppium supports and which method you need to implement for each command is to look at Appium's\n[routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js).\nEach route object in this file tells you the command name as well as the parameters you'd expect to\nreceive for that command.\n\nLet's take this block for example:\n```js\n'/session/:sessionId/url': {\n GET: {command: 'getUrl'},\n POST: {command: 'setUrl', payloadParams: {required: ['url']}},\n}\n```\n\nHere we see that the route `/session/:sessionId/url` is mapped to two commands, one for a `GET`\nrequest and one for a `POST` request. If we want to allow our driver to change the \"url\" (or\nwhatever that might mean for our driver), we can therefore implement the `setUrl` command, knowing\nit will take the `url` parameter:\n\n```js\nasync setUrl(url) {\n // your implementation here\n}\n```\n\nA few notes:\n- all command methods should be `async` functions or otherwise return a `Promise`\n- you don't need to worry about protocol encoding/decoding. You will get JS objects as params, and\n can return JSON-serializable objects in response. Appium will take care of wrapping it up in the\n WebDriver protocol response format, turning it into JSON, etc...\n- all session-based commands receive the `sessionId` parameter as the last parameter\n- all element-based commands receive the `elementId` parameter as the second-to-last parameter\n- if your driver doesn't implement a command, users can still try to access the command, and will\n get a `501 Not Yet Implemented` response error.","metadata":{"headerPath":"## Standard driver implementation ideas > ### Implement WebDriver classic commands","sectionCount":1,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Standard driver implementation ideas > ### Implement WebDriver BiDi commands\n\n[WebDriver BiDi](https://w3c.github.io/webdriver-bidi) is a newer version of the WebDriver spec\nwhich is implemented over Websockets instead of HTTP. As an Appium driver author you can take\nadvantage of Appium's BiDi support without having to know anything about the BiDi protocol or\nWebsockets. Implementing handlers for BiDi commands works just the same as implementing handlers\nfor WebDriver classic commands (described in the previous section). You simply define a method on\nyour driver of the appropriate name, and it will be called when the BiDi command is requested by\nthe client. To see which specific names you should use for BiDi commands, have a look at\n[bidi-commands.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/bidi-commands.js)\n\nYou are not limited to BiDi commands that are defined in the official BiDi specification. If you\nwish to define new commands, you may do so; you just need to tell Appium about them! See\n[below](#extend-the-existing-protocol-with-new-commands) for more information.\n\n## Standard driver implementation ideas > ### Implement element finding\n\nElement finding is a special command implementation case. You don't actually want to override\n`findElement` or `findElements`, even though those are what are listed in `routes.js`. Appium does\na lot of work for you if instead you implement this function:\n\n```js\nasync findElOrEls(strategy, selector, mult, context) {\n // find your element here\n}\n```\n\nHere's what gets passed in:\n\n- `strategy` - a string, the locator strategy being used\n- `selector` - a string, the selector\n- `mult` - boolean, whether the user has requested one element or all elements matching the\n selector\n- `context` - (optional) if defined, will be a W3C Element (i.e., a JS object with the W3C element\n identifier as the key and the element ID as the value)\n\nAnd you need to return one of the following:\n\n- a single W3C element (an object as described above)\n- an array of W3C elements\n\nNote that you can import that W3C web element identifier from `appium/support`:\n\n```js\nimport {util} from 'appium/support';\nconst { W3C_WEB_ELEMENT_IDENTIFIER } = util;\n```\n\nWhat you do with elements is up to you! Usually you end up keeping a cache map of IDs to actual\nelement \"objects\" or whatever the equivalent is for your platform.","metadata":{"headerPath":"## Standard driver implementation ideas > ### Implement WebDriver BiDi commands","sectionCount":2,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Standard driver implementation ideas > ### Define valid locator strategies\n\nYour driver might only support a subset of the standard WebDriver locator strategies, or it might\nadd its own custom locator strategies. To tell Appium which strategies are considered valid for\nyour driver, create an array of strategies and assign it to `this.locatorStrategies`:\n\n```js\nthis.locatorStrategies = ['xpath', 'custom-strategy'];\n```\n\nAppium will throw an error if the user attempts to use any strategies other than the allowed ones,\nwhich enables you to keep your element finding code clean and deal with only the strategies you\nknow about.\n\nBy default, the list of valid strategies is empty, so if your driver isn't simply proxying to\nanother WebDriver endpoint, you'll need to define some. The protocol-standard locator strategies\nare defined [here](https://www.w3.org/TR/webdriver/#locator-strategies).\n\n## Standard driver implementation ideas > ### Throw WebDriver-specific errors\n\nThe WebDriver spec defines a [set of error\ncodes](https://github.com/jlipps/simple-wd-spec#error-codes) to accompany command responses if an\nerror occurred. Appium has created error classes for each of these codes, so you can throw the\nappropriate error from inside a command, and it will do the right thing in terms of the protocol\nresponse to the user. To get access to these error classes, import them from `appium/driver`:\n\n```\nimport {errors} from 'appium/driver';\n\nthrow new errors.NoSuchElementError();\n```\n\n## Standard driver implementation ideas > ### Log messages to the Appium log\n\nYou can always use `console.log`, of course, but Appium provides a nice logger for you as\n`this.log` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log\nlevels). If you want to create an Appium logger outside of a driver context (say in a script or\nhelper file), you can always construct your own too:\n\n```js\nimport {logging} from 'appium/support';\nconst log = logging.getLogger('MyDriver');\n```\n\n## Further possibilities for Appium drivers\n\nThese are things your driver *can* do to take advantage of extra driver features or do its job more\nconveniently.","metadata":{"headerPath":"## Standard driver implementation ideas > ### Define valid locator strategies","sectionCount":4,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Add a schema for custom command line arguments\n\nYou can add custom CLI args if you want your driver to receive data from the command line when the\nAppium server is started (for example, ports that a server administrator should set that should not\nbe passed in as capabilities.\n\nTo define CLI arguments (or configuration properties) for the Appium server, your extension must provide a _schema_. In\nthe `appium` property of your extension's `package.json`, add a `schema` property. This will either\na) be a schema itself, or b) be a path to a schema file.\n\nThe rules for these schemas:\n\n- Schemas must conform to [JSON Schema Draft-07](https://ajv.js.org/json-schema.html#draft-07).\n- If the `schema` property is a path to a schema file, the file must be in JSON or JS (CommonJS) format.\n- Custom `$id` values are unsupported. To use `$ref`, provide a value relative to the schema root, e.g., `/properties/foo`.\n- Known values of the `format` keyword are likely supported, but various other keywords may be unsupported. If you find a keyword that is unsupported which you need to use, please [ask for support](https://github.com/appium/appium/issues/new) or send a PR!\n- The schema must be of type `object` (`{\"type\": \"object\"}`), containing the arguments in a `properties` keyword. Nested properties are unsupported.\n\nExample:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"test-web-server-port\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 65535,\n \"description\": \"The port to use for the test web server\"\n },\n \"test-web-server-host\": {\n \"type\": \"string\",\n \"description\": \"The host to use for the test web server\",\n \"default\": \"sillyhost\"\n }\n }\n}\n```\n\nThe above schema defines two properties which can be set via CLI argument or configuration file. If\nthis extension is a _driver_ and its name is \"horace\", the CLI args would be\n`--driver-horace-test-web-server-port` and `--driver-horace-test-web-server-host`, respectively.\nAlternatively, a user could provide a configuration file containing:\n\n```json\n{\n \"server\": {\n \"driver\": {\n \"horace\": {\n \"test-web-server-port\": 1234,\n \"test-web-server-host\": \"localhorse\"\n }\n }\n }\n}\n```","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Add a schema for custom command line arguments","sectionCount":1,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Add driver scripts\n\nSometimes you might want users of your driver to be able to run scripts outside the context of\na session (for example, to run a script that pre-builds aspects of your driver). To support this,\nyou can add a map of script names and JS files to the `scripts` field within your Appium extension\nmetadata. So let's say you've created a script in your project that lives in a `scripts` directory\nin your project, named `driver-prebuild.js`. Then you could add a `scripts` field like this:\n\n```json\n{\n \"scripts\": {\n \"prebuild\": \"./scripts/driver-prebuild.js\"\n }\n}\n```\n\nNow, assuming your driver is named `mydriver`, users of your driver can run `appium driver run\nmydriver prebuild`, and your script will execute.","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Add driver scripts","sectionCount":1,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Proxy commands to another WebDriver implementation\n\nA very common design architecture for Appium drivers is to have some kind of platform-specific\nWebDriver implementation that the Appium driver interfaces with. For example, the Appium\nUiAutomator2 driver interfaces with a special (Java-based) server running on the Android device. In\nwebview mode, it also interfaces with Chromedriver.\n\nIf you find yourself in this situation, it is extremely easy to tell Appium that your driver is\njust going to be proxying WebDriver commands straight to another endpoint.\n\nFirst, let Appium know that your driver *can* proxy by implementing the `canProxy` method:\n\n```js\ncanProxy() {\n return true;\n}\n```\n\nNext, tell Appium which WebDriver routes it should *not* attempt to proxy (there often end up being\ncertain routes that you don't want to forward on):\n\n```js\ngetProxyAvoidList() {\n return [\n ['POST', new RegExp('^/session/[^/]+/appium')]\n ];\n}\n```\n\nThe proxy avoidance list should be an array of arrays, where each inner array has an HTTP method as\nits first member, and a regular expression as its second. If the regular expression matches the\nroute, then the route will not be proxied and instead will be handled by your driver. In this\nexample, we are avoiding proxying all `POST` routes that have the `appium` prefix.\n\nNext, we have to set up the proxying itself. The way to do this is to use a special class from\nAppium called `JWProxy`. (The name means \"JSON Wire Proxy\" and is related to a legacy\nimplementation of the protocol). You'll want to create a `JWProxy` object using the details required to\nconnect to the remote server:\n\n```js\n// import {JWProxy} from 'appium/driver';\n\nconst proxy = new JWProxy({\n server: 'remote.server',\n port: 1234,\n base: '/',\n});\n\nthis.proxyReqRes = proxy.proxyReqRes.bind(proxy);\nthis.proxyCommand = proxy.command.bind(proxy);\n```\n\nHere we are creating a proxy object and assigning some of its methods to `this` under the names\n`proxyReqRes` and `proxyCommand`. This is required for Appium to use the proxy, so don't forget\nthis step! The `JWProxy` has a variety of other options which you can check out in the source code,\nas well. (TODO: publish options as API docs and link here).\n\nFinally, we need a way to tell Appium when the proxy is active. For your driver it might always\nbe active, or it might only be active when in a certain context. You can define the logic as an\nimplementation of `proxyActive`:\n\n```js\nproxyActive() {\n return true; // or use custom logic\n}\n```","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Proxy commands to another WebDriver implementation","sectionCount":1,"recursiveSplit":true,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Proxy commands to another WebDriver implementation\n\n```js\nproxyActive() {\n return true; // or use custom logic\n}\n```\n\nWith those pieces in play, you won't have to reimplement anything that's already implemented by the\nremote endpoint you're proxying to. Appium will take care of all the proxying for you.","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Proxy commands to another WebDriver implementation","sectionCount":1,"recursiveSplit":true,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Proxy BiDi commands to another BiDi implementation\n\nAll of the above about proxying WebDriver commands is conceptually also valid for proxying BiDi\ncommands specifically. In order to enable BiDi proxying, you need to implement `get bidiProxyUrl`\non your driver. This should return a Websocket URL which is the address of the upstream socket you\nwant BiDi commands to be proxied to.\n\nThe intended pattern here is for you to start a session on the upstream implementation, check\nwhether it has an active BiDi socket in the returned capabilities (e.g., the `webSocketUrl`\ncapability), and then to set an internal field to that value, so that it can be returned by `get\nbidiProxyUrl`. Once all this is in place, Appium will proxy BiDi commands from the client straight\nto the upstream connection.","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Proxy BiDi commands to another BiDi implementation","sectionCount":1,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Extend the existing protocol with new commands\n\nYou may find that the existing commands don't cut it for your driver. If you want to expose\nbehaviours that don't map to any of the existing commands, you can create new commands in one of\nthree ways:\n\n1. Extending the classic WebDriver protocol and creating client-side plugins to access the extensions via the classic HTTP interface\n1. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface\n1. Overloading the Execute Script command by defining [Execute\n Methods](../guides/execute-methods.md)\n\nIf you want to follow the first path, you can direct Appium to recognize new methods and add them\nto its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`\nstatic variable in your driver class to an object of the same form as Appium's `routes.js` object.\nFor example, here is the `newMethodMap` for the `FakeDriver` example driver:\n\n```js\nstatic newMethodMap = {\n '/session/:sessionId/fakedriver': {\n GET: {command: 'getFakeThing'},\n POST: {command: 'setFakeThing', payloadParams: {required: ['thing']}},\n },\n '/session/:sessionId/fakedriverargs': {\n GET: {command: 'getFakeDriverArgs'},\n },\n};\n```\n\nIn this example we're adding a few new routes and a total of 3 new commands. For more examples of\nhow to define commands in this way, it's best to have a look through `routes.js`. Now all you need\nto do is implement the command handlers in the same way you'd implement any other Appium command.\n\nThe downside of this way of adding new commands is that people using the standard Appium clients\nwon't have nice client-side functions designed to target these endpoints. So you would need to\ncreate and release client-side plugins for each language you want to support (directions or\nexamples can be found at the relevant client docs).\n\nThe second way of adding new commands is adding them as BiDi commands (accessed via the BiDi\nwebsocket interface, rather than the classic HTTP interface). BiDi commands come in two parts:\na \"module\", which is basically a container or namespace, and a \"command\", which is the name of your\nnew command.","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Extend the existing protocol with new commands","sectionCount":1,"recursiveSplit":true,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Extend the existing protocol with new commands\n\nAs with the first method, you teach Appium to recognize your new BiDi commands by adding a static\nfield to your driver class, called `newBidiCommands`. It has a format similar to `newMethodMap`.\nBasically it encapsulates information about the BiDi module, BiDi command name, reference to your\ndriver instance method that will handle the command, and required and optional parameters. Here's\nan example of a `newBidiCommands` as implemented on an imaginary driver:\n\n```js\nstatic newBidiCommands = {\n 'appium:video': {\n startFramerateCapture: {\n command: 'startFrameCap',\n params: {\n required: ['videoSource'],\n optional: ['showOnScreen'],\n }\n },\n stopFramerateCapture: {\n command: 'stopFrameCap',\n },\n }\n};\n```\n\nIn this imaginary example, we have defined two new BiDi commands:\n`appium:video.startFramerateCapture` and `appium:video.stopFramerateCapture`. Note first of all\nthat, because we are defining a custom BiDi command, we should include a 'vendor prefix' (in this\ncase, `appium:`, though you should pick something that represents your project). The first command\ntakes a required and an optional parameter, and the second does not. When combined with generic\nBiDi support in your driver (see [the section on BiDi](#implement-webdriver-bidi-commands) above),\nand given an implementation of the appropriate methods on your driver (e.g. `startFrameCap` and\n`stopFrameCap` in this example), clients would be able to send these BiDi commands using whatever\nmechanism normally exists for doing so in the client library.\n\nAn alternative to these other ways of doing things is to overload a command which all WebDriver clients\nhave access to already: Execute Script. Appium provides some a convenient tool for making this\neasy. Let's say you are building a driver for stereo system called `soundz`, and you wanted to\ncreate a command for playing a song by name. You could expose this to your users in such a way that\nthey call something like:\n\n```js\n// webdriverio example. Calling webdriverio's `executeScript` command is what trigger's Appium's\n// Execute Script command handler\ndriver.executeScript('soundz: playSong', [{song: 'Stairway to Heaven', artist: 'Led Zeppelin'}]);\n```","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Extend the existing protocol with new commands","sectionCount":1,"recursiveSplit":true,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Extend the existing protocol with new commands\n\nThen in your driver code you can define the static property `executeMethodMap` as a mapping of\nscript names to methods on your driver. It has the same basic form as `newMethodMap`, described\nabove. Once `executeMethodMap` is defined, you'll also need to implement the Execute Script command\nhandler, which according to Appium's routes mapping is called `execute`. The implementation can\ncall a single helper function, `this.executeMethod`, which takes care of looking at the script and\narguments the user sent in and routing it to the correct custom handler you've defined. Here's an\nexample:\n\n```js\nstatic executeMethodMap = {\n 'soundz: playSong', {\n command: 'soundzPlaySong',\n params: {required: ['song', 'artist'], optional: []},\n }\n}\n\nasync soundzPlaySong(song, artist) {\n // play the song based on song and artist details\n}\n\nasync execute(script, args) {\n return await this.executeMethod(script, args);\n}\n```\n\nA couple notes about this system:\n1. The arguments array sent via the call to Execute Script must contain only zero or one element(s). The\n first item in the list is considered to be the parameters object for your method. These parameters\n will be parsed, validated, and then applied to your overload method in the order specified in\n `executeMethodMap` (the order specified in the `required` parameters list, followed by the\n `optional` parameters list). I.e., this framework assumes only a single actual argument sent in via\n Execute Script (and this argument should be an object with keys/values representing the\n parameters your execute method expects).\n1. Appium does not automatically implement `execute` (the Execute Script handler) for you. You may\n wish, for example, to only call the `executeMethod` helper function when you're not in proxy\n mode!\n1. The `executeMethod` helper will reject with an error if a script name doesn't match one of the\n script names defined as a command in `executeMethodMap`, or if there are missing parameters.\n\nOne of the nice things about the Execute Method strategy is that methods implemented in this way\nwill be available via the classic or BiDi interfaces (since they will result in the same Appium\nhandlers being called).","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Extend the existing protocol with new commands","sectionCount":1,"recursiveSplit":true,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Build Appium Doctor checks\n\nYour users can run `appium driver doctor <driverName>` to run installation and health checks. Visit\nthe [Building Doctor Checks](./build-doctor-checks.md) guide for more information on this\ncapability.\n\n## Further possibilities for Appium drivers > ### Implement handling of Appium settings\n\nAppium users can send parameters to your driver via CLI args as well as via capabilities. But these\ncannot change during the course of a test, and sometimes users want to adjust parameters mid-test.\nAppium has a [Settings](../guides/settings.md) API for this purpose.\n\nTo support settings in your own driver, first of all define `this.settings` to be an instance of\nthe appropriate class, in your constructor:\n\n```js\n// import {DeviceSettings} from 'appium/driver';\n\nthis.settings = new DeviceSettings();\n```\n\nNow, you can read user settings any time simply by calling `this.settings.getSettings()`. This will\nreturn a JS object where the settings names are keys and have their corresponding values.\n\nIf you want to assign some default settings, or run some code on your end whenever settings are\nupdated, you can do both of these things as well.\n\n```js\nconstructor() {\n const defaults = {setting1: 'value1'};\n this.settings = new DeviceSettings(defaults, this.onSettingsUpdate.bind(this));\n}\n\nasync onSettingsUpdate(key, value) {\n // do anything you want here with key and value\n}\n```\n\n## Further possibilities for Appium drivers > ### Emit BiDi events\n\nWith the WebDriver BiDi protocol, clients can subscribe to arbitrary events which can be sent\nasynchronously to the client over the BiDi socket connection. As an Appium driver author you don't\nneed to worry about event subscription. If you want to emit an event with a certain method name and\npayload, it's as easy as using the built-in event emitter with the `bidiEvent` event.\n\nAs an\nexample, let's say our driver wants to periodically emit CPU load information. We could define an\nevent called `system.cpu`, and a payload that looks like `{load: 0.97}` to signify 97% CPU usage.\nWhenever we want, our driver can simply call the following code (assuming we have the current load\nin `this.currentCpuLoad`):\n\n```js\nthis.eventEmitter.emit('bidiEvent', {\n method: 'appium:system.cpu',\n params: {load: this.currentCpuLoad},\n})\n```\n\nNow, if the client has subscribed to the `system.cpu` event, it will be notified with the load\nwhenever the driver emits it.","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Build Appium Doctor checks","sectionCount":3,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Make itself aware of resources other concurrent drivers are using\n\nLet's say your driver uses up some system resources, like ports. There are a few ways to make sure\nthat multiple simultaneous sessions don't use the same resources:\n\n1. Have your users specify resource IDs via capabilities (`appium:driverPort` etc)\n1. Just always use free resources (find a new random port for each session)\n1. Have each driver express what resources it is using, then examine currently-used resources from\n other drivers when a new session begins.\n\nTo support this third strategy, you can implement `get driverData` in your driver to return what\nsorts of resources your driver is currently using, for example:\n\n```js\nget driverData() {\n return {specialPort: 1234, specialFile: /path/to/file}\n}\n```\n\nNow, when a new session is started on your driver, the `driverData` response from any other\nsimultaneously running drivers (of the same type) will also be included, as the last parameter of\nthe `createSession` method:\n\n```js\nasync createSession(jwpCaps, reqCaps, w3cCaps, driverData)\n```\n\nYou can dig into this `driverData` array to see what resources other drivers are using to help\ndetermine which ones you want to use for this particular session.\n\n!!! warning\n\n Be careful here, since `driverData` is only passed between sessions of a single running Appium\n server. There's nothing to stop a user from running multiple Appium servers and requesting your\n driver simultaneously on each of them. In this case, you won't be able to ensure independence\n of resources via `driverData`, so you might consider using file-based locking mechanisms or\n something similar.\n\n!!! warning\n\n It's also important to note you will only receive `driverData` for other instances of *your*\n driver. So unrelated drivers also running may still be using some system resources. In general\n Appium doesn't provide any features for ensuring unrelated drivers don't interfere with one\n another, so it's up to the drivers to allow users to specify resource locations or addresses to\n avoid clashes.","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Make itself aware of resources other concurrent drivers are using","sectionCount":1,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Log events to the Appium event timeline\n\nAppium has an [Event Timing API](../guides/event-timing.md) which allows users to get timestamps\nfor certain server-side events (like commands, startup milestones, etc...) and display them on\na timeline. The feature basically exists to allow introspection of timing for internal events to\nhelp with debugging or running analysis on Appium driver internals. You can add your own events to\nthe event log:\n\n```js\nthis.logEvent(name);\n```\n\nSimply provide a name for the event and it will be added at the current time, and made accessible\nas part of the event log for users.\n\n## Further possibilities for Appium drivers > ### Hide behaviour behind security flags\n\nAppium has a feature-flag based [security model](../guides/security.md) that allows driver authors\nto hide certain features behind security flags. What this means is that if you have a feature you\ndeem insecure and want to require server admins to opt in to it, you can require that they enable\nthe feature by adding it to the `--allow-insecure` list or turning off server security entirely.\n\nTo support the check within your own driver, you can call `this.isFeatureEnabled(featureName)` to\ndetermine whether a feature of the given name has been enabled. Or, if you want to simply\nshort-circuit and throw an error if the feature isn't enabled, you can call\n`this.assertFeatureEnabled(featureName)`.\n\n## Further possibilities for Appium drivers > ### Use a temp dir for files\n\nIf you want to use a temporary directory for files your driver creates that are not important to\nkeep around between computer or server restarts, you can simply read from `this.opts.tmpDir`. This\nreads the temporary directory location from `@appium/support`, potentially overridden by a CLI\nflag. I.e., it's safer than writing to your own temporary directory because the location here plays\nnicely with possible user configuration. `this.opts.tmpDir` is a string, the path to the dir.","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Log events to the Appium event timeline","sectionCount":3,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"## Further possibilities for Appium drivers > ### Deal with unexpected shutdowns or crashes\n\nYour driver might run into a situation where it can't continue operating normally. For example, it\nmight detect that some external service has crashed and nothing will work anymore. In this case, it\ncan call `this.startUnexpectedShutdown(err)` with an error object including any details, and Appium\nwill attempt to gracefully handle any remaining requests before shutting down the session.\n\nIf you want to perform some of your own cleanup logic when you encounter this condition, you can\neither do so immediately before calling `this.startUnexpectedShutdown`, or you can attach a handler\nto the unexpected shutdown event and run your cleanup logic \"out of band\" so to speak:\n\n```js\nthis.onUnexpectedShutdown(handler)\n```\n\n`handler` should be a function which receives an error object (representing the reason for the\nunexpected shutdown).","metadata":{"headerPath":"## Further possibilities for Appium drivers > ### Deal with unexpected shutdowns or crashes","sectionCount":1,"filename":"build-drivers.md","relativePath":"appium/packages/appium/docs/en/developing/build-drivers.md"}},{"pageContent":"---\ntitle: Building Plugins\n---\n\nThis is a high-level guide for developing Appium plugins, which is not something most Appium users\nneed to know or care about. If you are not familiar with Appium plugins yet from a user\nperspective, check out the [list of plugins](../ecosystem/plugins.md) to play around with some and get\nan idea of the sorts of things that plugins can do. Plugins are a powerful system for augmenting\nAppium's functionality or changing the way Appium works. They can be distributed to other Appium\nusers and can extend Appium's ecosystem in all kinds of interesting ways! (There is also\na significant amount of overlap here with developing Appium drivers, so you may also want to check\nout the [building drivers](./build-drivers.md) guide for further inspiration.)\n\n## Before you create your plugin\n\nBefore creating your plugin, it's good to have a general idea of what you want your plugin to\naccomplish and whether it will be possible to implement it given the restrictions of the Appium\nplatform. Reading through this guide will help you understand what's possible. In general, Appium's\nplugin system is extremely powerful and no attempts have been made to artificially limit what's\npossible with them (which is a main reason that all plugins are opt-in by the system administrator\nresponsible for starting the Appium server---plugins are powerful and should only be used when\nexplicitly trusted!).\n\n## Other plugins to reference\n\nThere are a wide variety of open source Appium plugins available for perusal. It's definitely\nrecommended to explore the code for some other plugins before embarking on writing your own. The\nAppium team maintains a set of official plugins in the [Appium GitHub\nrepo](https://github.com/appium/appium). Links to other open source plugins can be found in the\n[Plugin list](../ecosystem/plugins.md)\n\n## Basic requirements for plugins\n\nThese are the things your plugin *must* do (or be), if you want it to be a valid Appium plugin.","metadata":{"headerPath":"","sectionCount":4,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Basic requirements for plugins > ### Node.js package with Appium extension metadata\n\nAll Appium plugins are fundamentally Node.js packages, and therefore must have a valid\n`package.json`. Your driver is not _limited_ to Node.js, but it must provide an adapter written in\nNode.js so it can be loaded by Appium.\n\nYour `package.json` must include `appium` as a `peerDependency`. The requirements for the\ndependency versions should be as loose as possible (unless you happen to know your plugin will only\nwork with certain versions of Appium). For Appium 2, for example, this would look something like\n`^2.0.0`, declaring that your plugin works with any version of Appium that starts with 2.x.\n\nYour `package.json` must contain an `appium` field, like this (we call this the 'Appium extension\nmetadata'):\n\n ```json\n {\n ...,\n \"appium\": {\n \"pluginName\": \"fake\",\n \"mainClass\": \"FakePlugin\"\n },\n ...\n }\n ```\n\nThe required subfields are:\n\n* `pluginName`: this should be a short name for your plugin.\n* `mainClass`: this is a named export (in CommonJS style) from your `main` field. It must be a\n class which extends Appium's `BasePlugin` (see below).\n\n## Basic requirements for plugins > ### Extend Appium's `BasePlugin` class\n\nUltimately, your plugin is much easier to write because most of the hard work of defining patterns\nfor overriding commands is done for you. This is\nall encoded up as a class which Appium exports for you to use, called `BasePlugin`. It is exported\nfrom `appium/plugin`, so you can use one of these styles to import it and create your *own* class\nthat extends it:\n\n```js\nimport {BasePlugin} from 'appium/plugin';\n// or: const {BasePlugin} = require('appium/plugin');\n\nexport class MyPlugin extends BasePlugin {\n // class methods here\n}\n```\n\n!!! note\n\n In all the code samples below, whenever we reference an example method, it is assumed\n that it is defined _within_ the class, though this is not explicitly written, for the sake of\n clarity and space.","metadata":{"headerPath":"## Basic requirements for plugins > ### Node.js package with Appium extension metadata","sectionCount":2,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Basic requirements for plugins > ### Make your plugin available\n\nThat's basically it! With a Node.js package exporting a plugin class and with correct Appium\nextension metadata, you've got yourself an Appium plugin! Now it doesn't *do* anything, but you can\nload it up in Appium, activate it, etc...\n\nTo make it available to users, you could publish it via NPM. When you do so, your plugin will be\ninstallable via the Appium CLI:\n\n```\nappium plugin install --source=npm <plugin-package-on-npm>\n```\n\nIt's a good idea to test your plugin first, of course. One way to see how it works within Appium is\nto install it locally first:\n\n```\nappium plugin install --source=local /path/to/your/plugin\n```\n\nAnd of course, plugins must be \"activated\" during Appium server start, so make sure you direct your\nusers to do so:\n\n```\nappium --use-plugins=plugin-name\n```\n\n## Basic requirements for plugins > ### Developing your plugin\n\nHow you develop your plugin is up to you. It is convenient, however, to run it from within Appium\nwithout having to do lots of publishing and installing. The most straightforward way to do this is\nto include the most recent version of Appium as a `devDependency` (although its being already\nincluded as a `peerDependency` is sufficient in newer versions of NPM), and then also your own plugin,\nlike this:\n\n```json\n{\n \"devDependencies\": {\n ...,\n \"appium\": \"^2.0.0\",\n \"your-plugin\": \"file:.\",\n ...\n }\n}\n```\n\nNow, you can run Appium locally (`npm exec appium` or `npx appium`), and because your plugin is\nlisted as a dependency alongside it, it will be automatically \"installed\" and available. You can\ndesign your e2e tests this way, or if you're writing them in Node.js, you can simply import\nAppium's start server methods to handle starting and stopping the Appium server in Node.\n\nOf course, you can always install it locally as described above as well.\n\nAnytime you make changes to your plugin code, you'll need to restart the Appium server to make sure\nit picks up the latest code. As with drivers, you can set the `APPIUM_RELOAD_EXTENSIONS`\nenvironment variable if you wish Appium to try to re-require your plugin module when a new session\nstarts.\n\n## Standard plugin implementation ideas\n\nThese are things you will probably find yourself wanting to do when creating a plugin.","metadata":{"headerPath":"## Basic requirements for plugins > ### Make your plugin available","sectionCount":3,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Standard plugin implementation ideas > ### Set up state in a constructor\n\nIf you define your own constructor, you'll need to call `super` to make sure all the standard state\nis set up correctly:\n\n```js\nconstructor(...args) {\n super(...args);\n // now do your own thing\n}\n```\n\nThe `args` parameter here is the object containing all the CLI args used to start the Appium\nserver.\n\n## Standard plugin implementation ideas > ### Intercept and handle specific Appium commands\n\nThis is the most normal behavior for Appium plugins -- to modify or replace the execution of one or\nmore commands that would normally be handled by the active driver. To override the default command\nhandling, you need to implement `async` methods in your class with the same name as the Appium\ncommands to be handled (just exactly how [drivers themselves are\nimplemented](./build-drivers.md#implement-webdriver-classic-commands)). Curious what command names there\nare? They are defined in the Appium base driver's\n[routes.js](https://github.com/appium/appium-base-driver/blob/master/lib/protocol/routes.js) file,\nand of course you can add more as defined in the next section.\n\nEach command method is sent the following arguments:\n\n1. `next`: This is a reference to an `async` function which encapsulates the chain of behaviors which would take place if this plugin were not handling the command. You can choose to call the next behavior in the chain at any point in your logic (by making sure to include `await next()` somewhere), or not. If you don't, it means the default behavior (or any plugins registered after this one) won't be run.\n1. `driver`: This is the object representing the driver handling the current session. You have access to it for any work you need to do, for example calling other driver methods, checking capabilities or settings, etc...\n1. `...args`: A spread array with any arguments that have been applied to the command by the user.\n\nFor example, if we wanted to override the `setUrl` command to simply add some extra logging on top,\nwe would implement as follows:\n\n```js\nasync setUrl(next, driver, url) {\n this.log(`Let's get the page source for some reason before navigating to '${url}'!`);\n await driver.getPageSource();\n const result = await next();\n this.log(`We can also log after the original behaviour`);\n return result;\n}\n```","metadata":{"headerPath":"## Standard plugin implementation ideas > ### Set up state in a constructor","sectionCount":2,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Standard plugin implementation ideas > ### Intercept and handle _all_ Appium commands\n\nYou might find yourself in a position where you want to handle *all* commands, in order to inspect\npayloads to determine whether or not to act in some way. If so, you can implement `async handle`,\nand any command that is not handled by one of your named methods will be handled by this method\ninstead. It takes the following parameters (with all the same semantics as above):\n\n1. `next`\n1. `driver`\n1. `cmdName` - string representing the command being run\n1. `...args`\n\nFor example, let's say we want to log timing for all Appium commands as part of a plugin. We could\ndo this by implementing `handle` in our plugin class as follows:\n\n```js\nasync handle(next, driver, cmdName, ...args) {\n const start = Date.now();\n try {\n const result = await next();\n } finally {\n const elapsedMs = Date.now() - start;\n this.log(`Command '${cmdName}' took ${elapsedMs}`);\n }\n return result;\n}\n```\n\n## Standard plugin implementation ideas > ### Working with driver proxies\n\nThere is a bit of a gotcha with handling Appium commands. Appium drivers have the ability to turn\non a special 'proxy' mode, wherein the Appium server process takes a look at incoming URLs, and\ndecides whether to forward them on to some upstream WebDriver server. It could happen that\na command which a plugin wants to handle is designated as a command which is being proxied to an\nupstream server. In this case, we might run into a problem, because the plugin never gets a chance to\nhandle that command! The way Appium handles this is as follows:\n\n1. When a command comes in, before deciding whether to proxy the command, the main protocol handler\n checks to see whether a plugin would handle the command.\n2. If a plugin would *not* handle the command--all proceeds as normal, and the request is either\n proxied or not, based on the driver's proxy mode.\n3. If a plugin *would* handle the command, then the proxy behavior is skipped for the time being,\n and wrapped up as the `next` function sent to the plugin. So if you have a command handler in\n your plugin, and you want to be sure that the default driver proxying *does* take place, then\n simply `await next()` instead of (or in addition to) whatever your plugin handler is doing.","metadata":{"headerPath":"## Standard plugin implementation ideas > ### Intercept and handle _all_ Appium commands","sectionCount":2,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Standard plugin implementation ideas > ### Throw WebDriver-specific errors\n\nThe WebDriver spec defines a [set of error\ncodes](https://github.com/jlipps/simple-wd-spec#error-codes) to accompany command responses if an\nerror occurred. Appium has created error classes for each of these codes, so you can throw the\nappropriate error from inside a command, and it will do the right thing in terms of the protocol\nresponse to the user. To get access to these error classes, import them from `appium/driver`:\n\n```js\nimport {errors} from 'appium/driver';\n\nthrow new errors.NoSuchElementError();\n```\n\n## Standard plugin implementation ideas > ### Log messages to the Appium log\n\nYou can always use `console.log`, of course, but Appium provides a nice logger for you as\n`this.logger` (it has `.info`, `.debug`, `.log`, `.warn`, `.error` methods on it for differing log\nlevels). If you want to create an Appium logger outside of a plugin context (say in a script or\nhelper file), you can always construct your own too:\n\n```js\nimport {logging} from 'appium/support';\nconst log = logging.getLogger('MyPlugin');\n```\n\n## Further possibilities for Appium plugins\n\nThese are things your plugin *can* do to take advantage of extra plugin features or do its job more\nconveniently.\n\n## Further possibilities for Appium plugins > ### Add a schema for custom command line arguments\n\nYou can add custom CLI args if you want your plugin to receive data from the command line when the\nAppium server is started (for example, ports that a server administrator should set that should not\nbe passed in as capabilities).\n\nThis works largely the same for plugins as it does for drivers, so for more details have a look at\n[the equivalent section in the building drivers\ndoc](./build-drivers.md#add-a-schema-for-custom-command-line-arguments).\n\nThe only difference is that to construct the CLI argument name, you prefix it with\n`--plugin-<name>`. So for example, if you have a plugin named `pluggo` and a CLI arg defined with\nthe name `electro-port`, you can set it when starting Appium via `--plugin-pluggo-electro-port`.\n\nSetting args via a configuration file is also supported, as it is for drivers, but under the\n`plugin` field instead. For example:\n\n```json\n{\n \"server\": {\n \"plugin\": {\n \"pluggo\": {\n \"electro-port\": 1234\n }\n }\n }\n}\n```","metadata":{"headerPath":"## Standard plugin implementation ideas > ### Throw WebDriver-specific errors","sectionCount":4,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Further possibilities for Appium plugins > ### Add plugin scripts\n\nSometimes you might want users of your plugin to be able to run scripts outside the context of\na session (for example, to run a script that pre-builds aspects of your plugin). To support this,\nyou can add a map of script names and JS files to the `scripts` field within your Appium extension\nmetadata. So let's say you've created a script in your project that lives in a `scripts` directory\nin your project, named `plugin-prebuild.js`. Then you could add a `scripts` field like this:\n\n```json\n{\n \"scripts\": {\n \"prebuild\": \"./scripts/plugin-prebuild.js\"\n }\n}\n```\n\nNow, assuming your plugin is named `myplugin`, users of your plugin can run `appium plugin run\nmyplugin prebuild`, and your script will execute.\n\n## Further possibilities for Appium plugins > ### Add new Appium commands\n\nIf you want to offer functionality that doesn't map to any of the existing commands supported by\ndrivers, you can create new commands in one of two ways, just as is possible for drivers:\n\n1. Extending the WebDriver protocol and creating client-side plugins to access the extensions\n1. Extending the WebDriver BiDi protocol with new modules and methods, accessed from a client via the BiDi interface\n1. Overloading the Execute Script command by defining [Execute\n Methods](../guides/execute-methods.md)","metadata":{"headerPath":"## Further possibilities for Appium plugins > ### Add plugin scripts","sectionCount":2,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Further possibilities for Appium plugins > ### Add new Appium commands > #### Extending the HTTP Protocol\n\nIf you want to follow the first path, you can direct Appium to recognize new methods and add them\nto its set of allowed HTTP routes and command names. You do this by assigning the `newMethodMap`\nstatic variable in your driver class to an object of the same form as Appium's `routes.js` object.\nFor example, here is part of the `newMethodMap` for the `FakePlugin` example driver:\n\n```js\nstatic newMethodMap = {\n '/session/:sessionId/fake_data': {\n GET: {command: 'getFakeSessionData', neverProxy: true},\n POST: {\n command: 'setFakeSessionData',\n payloadParams: {required: ['data']},\n neverProxy: true,\n },\n },\n '/session/:sessionId/fakepluginargs': {\n GET: {command: 'getFakePluginArgs', neverProxy: true},\n },\n};\n```\n\n!!! note\n\n If you're using TypeScript, static member objects like these should be defined `as const`.\n\nIn this example we're adding a few new routes and a total of 3 new commands. For more examples of\nhow to define commands in this way, it's best to have a look through `routes.js`. Now all you need\nto do is implement the command handlers in the same way you'd implement any other Appium command.\n\nNote also the special `neverProxy` key for commands; this is generally a good idea to set to `true`\nfor plugins, since your plugin might be active for a driver that is put into proxy mode but hasn't\nbothered to decline proxying for these (new and therefore unknown) commands. Setting `neverProxy`\nto `true` here will cause Appium to never proxy these routes and therefore ensure your plugin\nhandles them, even if a driver is in proxy mode.\n\nThe downside of adding new commands via `newMethodMap` is that people using the standard Appium\nclients won't have nice client-side functions designed to target these endpoints. So you would need\nto create and release client-side plugins for each language you want to support (directions or\nexamples can be found at the relevant client docs).","metadata":{"headerPath":"## Further possibilities for Appium plugins > ### Add new Appium commands > #### Extending the HTTP Protocol","sectionCount":1,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Further possibilities for Appium plugins > ### Add new Appium commands > #### Extending the BiDi Protocol\n\nYou can also make new commands accessible via the WebDriver BiDi (WebSocket-based) protocol. BiDi\ncommands come in two parts: a \"module\", which is basically a container or namespace, and\na \"command\", which is the name of your new command.\n\nAs with the first method, you teach Appium to recognize your new BiDi commands by adding a static\nfield to your driver class, called `newBidiCommands`. It has a format similar to `newMethodMap`.\nBasically it encapsulates information about the BiDi module, BiDi command name, reference to your\ndriver instance method that will handle the command, and required and optional parameters. Here's\nan example of a `newBidiCommands` as implemented on an imaginary driver:\n\n```js\nstatic newBidiCommands = {\n 'appium:video': {\n startFramerateCapture: {\n command: 'startFrameCap',\n params: {\n required: ['videoSource'],\n optional: ['showOnScreen'],\n }\n },\n stopFramerateCapture: {\n command: 'stopFrameCap',\n },\n }\n};\n```\n\nIn this imaginary example, we have defined two new BiDi commands: `appium:video.startFramerateCapture` and\n`appium:video.stopFramerateCapture`. The first command takes a required and an optional parameter, and the\nsecond does not. When you have implemented the `startFrameCap` and `stopFrameCap` methods on your\nplugin class, they will be called whenever the BiDi commands are triggered by a client. The\nsignatures for these methods would look as follows:\n\n```js\nasync startFrameCap(next: () => Promise<any>, driver: DriverClass, videoSource: string, showOnScreen: boolean): Promise<any>;\nasync stopFrameCap(next: () => Promise<any>, driver: DriverClass): Promise<any>;\n```\n\nAs with adding or overriding existing HTTP protocol commands, these methods are injected with\na `next` parameter and a `driver` parameter. The `driver` object represents the driver currently\nowning the session, and calling `await next()` will execute/return the behavior that would execute\nwere the plugin not active (i.e., the driver's own handling of that method, or the chain of\ncommands executed with the same name by other active plugins).\n\nNote that, currently, if a driver has BiDi proxying turned on, plugins will not be able to override\nBiDi methods handled by the proxy. Also note that since these are custom BiDi commands, our module\nname should include a vendor prefix (we chose `appium:`, but you can/should choose something that\nmakes sense for your extension).","metadata":{"headerPath":"## Further possibilities for Appium plugins > ### Add new Appium commands > #### Extending the BiDi Protocol","sectionCount":1,"recursiveSplit":true,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Further possibilities for Appium plugins > ### Add new Appium commands > #### Overloading Execute Script\n\nAn alternative to these ways of doing things is to overload a command which all WebDriver clients\nhave access to already: Execute Script. Make sure to read the section on [adding new\ncommands](./build-drivers.md#extend-the-existing-protocol-with-new-commands) in\nthe Building Drivers guide to understand the way this works in general. The way it works with\nplugins is only slightly different. Let's look at an example taken from Appium's `fake-plugin`:\n\n```js\nstatic executeMethodMap = {\n 'fake: plugMeIn': {\n command: 'plugMeIn',\n params: {required: ['socket']},\n },\n};\n\nasync plugMeIn(next, driver, socket) {\n return `Plugged in to ${socket}`;\n}\n\nasync execute(next, driver, script, args) {\n return await this.executeMethod(next, driver, script, args);\n}\n```\n\nWe have three important components shown here which make this system work, all of which are defined\ninside the plugin class:\n\n1. The `executeMethodMap`, defined in just the same way as for drivers\n1. The implementation of the command method as defined in `executeMethodMap` (in this case,\n `plugMeIn`)\n1. The overriding/handling of the `execute` command. Just like any plugin command handlers, the\nfirst two arguments are `next` and `driver`, followed by the script name and args. `BasePlugin`\nimplements a helper method which we can simply call with all of these arguments.\n\nOverriding Execute Methods from drivers works as you'd expect: if your plugin defines an Execute\nMethod with the same name as that of a driver, your command (in this case `plugMeIn`) will be\ncalled first. You can choose to run the driver's original behaviour via `next` if you want.\n\n## Further possibilities for Appium plugins > ### Emit BiDi Events\n\nYour plugin can emit custom BiDi events in [exactly the same way as Appium\ndrivers](./build-drivers.md#emit-bidi-events).\n\n## Further possibilities for Appium plugins > ### Build Appium Doctor checks\n\nYour users can run `appium plugin doctor <pluginName>` to run installation and health checks. Visit\nthe [Building Doctor Checks](./build-doctor-checks.md) guide for more information on this\ncapability.","metadata":{"headerPath":"## Further possibilities for Appium plugins > ### Add new Appium commands > #### Overloading Execute Script","sectionCount":3,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"## Further possibilities for Appium plugins > ### Update the Appium server object\n\nYou probably don't normally need to update the Appium server object (which is an\n[Express](https://expressjs.com/) server having already been\n[configured](https://github.com/appium/appium/blob/master/packages/base-driver/lib/express/server.js)\nin a variety of ways). But, for example, you could add new Express middleware to the server to\nsupport your plugin's requirements. To update the server you must implement the `static async\nupdateServer` method in your class. This method takes three parameters:\n\n* `expressApp`: the Express app object\n* `httpServer`: the Node HTTP server object\n* `cliArgs`: a map of the CLI args used to start the Appium server\n\nYou can do whatever you want with them inside the `updateServer` method. You might want to\nreference how these objects are created and worked with in the BaseDriver code, so that you know\nyou're not undoing or overriding anything standard and important. But if you insist, you can, with\nresults you'll need to test! Warning: this should be considered an advanced feature and requires\nknowledge of Express, as well as the care not to do anything that could affect the operation of\nother parts of the Appium server!\n\n## Further possibilities for Appium plugins > ### Handle unexpected session shutdown\n\nWhen developing a plugin you may want to add some cleanup logic for when a session ends. You would\nnaturally do this by adding a handler for `deleteSession`. This works in most cases, except when\nthe session does not finish cleanly. Appium sometimes determines that a session has finished\nunexpectedly, and in these situations, Appium will look for a method called `onUnexpectedShutdown`\nin your plugin class, which will be called (passing the current session driver as the first\nparameter, and the error object representing the cause of the shutdown as the second), giving you\nan opportunity to take any steps that might be necessary to clean up from the session. For example,\nkeeping in mind that the function is not `await`ed you could implement something like this:\n\n```js\nasync onUnexpectedShutdown(driver, cause) {\n try {\n // do some cleanup\n } catch (e) {\n // log any errors; don't allow anything to be thrown as they will be unhandled rejections\n }\n}\n```","metadata":{"headerPath":"## Further possibilities for Appium plugins > ### Update the Appium server object","sectionCount":2,"filename":"build-plugins.md","relativePath":"appium/packages/appium/docs/en/developing/build-plugins.md"}},{"pageContent":"---\ntitle: Appium's Config System\n---\n\nAppium includes support for [configuration files](../guides/config.md). A configuration file is\nintended to have (nearly) 1:1 parity with command-line arguments. An end user can supply Appium with\na configuration file, CLI args, or both (the args have precedence over the config file).\n\nThis document will be a technical overview of how the configuration system works. It is intended\nfor Appium contributors, but will also explain the system's fundamental features.\n\n## Reading a Config File\n\nA config file is a JSON, JavaScript, or YAML file which can be validated against a schema. By\ndefault, this file will be named `.appiumrc.{json,js,yaml,yml}` and should be in the root of the\nproject which depends upon `appium`. Other filenames and locations are supported via the `--config\n<file>` flag. For obvious reasons, the `config` argument is disallowed within config files.\n\nIn lieu of a separate file, configuration can be embedded in a project's `package.json` using the\n`appiumConfig` property, e.g.,:\n\n```json\n{\n \"appiumConfig\": {\n \"server\": {\n \"port\": 12345\n }\n }\n}\n```\n\nWhen an Appium server is started via the `appium` executable, the `init` function in `lib/main.js`\nwill call into `lib/config-file.js` to load and/or search for a configuration file and in\n`package.json`.\n\n!!! note\n\n It is not an error if configuration isn't found!\n\nThe [`lilconfig`](https://npm.im/lilconfig) package provides the search & load functionality; refer\nto its documentation for more information about the search paths. Additionally, Appium provides\nsupport for config files written in YAML via the package [`yaml`](https://npm.im/yaml).\n\nIf a config file is found and successfully [validated](#validation), the result will be merged with\na set of defaults and any additional CLI arguments. CLI arguments have precedence over config\nfiles, and config files have precedence over defaults.","metadata":{"headerPath":"","sectionCount":2,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Validation\n\nThe same system is used for _both_ validation of config files _and_ command-line arguments.\n\nThe package [`ajv`](https://npm.im/ajv) provides validation. Of course, to make `ajv` validate\nanything, it must be provided a _schema_.\n\nThe _base_ schema is a [JSON Schema\nDraft-7](https://json-schema.org/draft/2020-12/json-schema-core.html)-compliant object exported by\n`lib/schema/appium-config-schema.js`. This schema defines configuration _native to Appium_, and\nonly concerns its behavior as a _server_; it does not define configuration for any other\nfunctionality (e.g., the `plugin` or `driver` subcommands).\n\n!!! warning\n\n Note that this file is the _base_ schema; this will become painfully relevant.\n\nThis file is is _not_ a JSON file, because a) JSON is painful to work with for humans, b) is\nespecially reviled by @jlipps, and c) `ajv` accepts objects, not JSON files.\n\nIt is more straightforward to explain how config files are validated, so we'll start there.\n\n## Validation > ### Validating Config Files\n\nWhen a config file is found (`lib/config-file.js`), it will call the `validate` function exported\nfrom `lib/schema/schema.js` with the contents of the config file. In turn, this asks `ajv` to\nvalidate the data against the schema that Appium has provided it.\n\nIf the config file is invalid, errors will be generated to be displayed to the user. Finally, the\n`init` function will detect these errors, display them, and the process will exit.\n\nI hope that made sense, because this is the easy part.\n\n## Validation > ### Validating CLI Arguments\n\nAs mentioned earlier, the same system is used for validating both config files and CLI arguments.\n\nTotally not judging, but Appium uses [`argparse`](https://npm.im/argparse) for its CLI argument\nparsing. This package, and others like it, provides an API to define the arguments a command-line\nNode.js script accepts, and will ultimately return an object representation of the user-supplied\narguments.\n\nJust as the schema defines what's allowed in a config file, it also defines what's allowed on the\ncommand-line.","metadata":{"headerPath":"## Validation","sectionCount":3,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Validation > ### Validating CLI Arguments > #### Defining CLI Arguments via Schema\n\nCLI arguments must be _defined_ before their values can be validated.\n\nA JSON schema isn't a natural fit for defining CLI args--it needs some grease to make it work--but\nit's close enough that we can do so with an adapter and some custom metadata.\n\nIn `lib/cli/parser.js`, there's a wrapper around `argparse`'s `ArgumentParser`; it's called (wait\nfor it)... `ArgParser`. The wrapper exists because we're doing some custom things with `argparse`,\nbut is has nothing to do with the schema directly.\n\nAn `ArgParser` instance is created and its `parseArgs()` method is called with the raw CLI\narguments. The definition of the accepted arguments comes from `lib/cli/args.js` in part--here, all\nof the arguments _not_ intended for use with the `server` subcommand are hard-coded (e.g., the\n`driver` subcommand and _its_ subcommands). `args.js` also contains a function `getServerArgs()`,\nwhich in turn calls into `toParserArgs` in `lib/schema/cli-args.js`. `lib/schema/cli-args.js` can\nbe considered the \"adapter\" layer between `argparse` and the schema.\n\n`toParserArgs` uses the `flattenSchema` function exported by `lib/schema/schema.js`, which\n\"squashes\" the schema into a key/value representation. Then, `toParserArgs` iterates over each\nkey/value pair and \"converts\" it into a suitable `ArgumentOption` object for final handoff to\n`ArgParser`.\n\nThis adapter (`cli-args.js`) is where most of the mess is hidden; let's explore this rat's nest\na bit further.","metadata":{"headerPath":"## Validation > ### Validating CLI Arguments > #### Defining CLI Arguments via Schema","sectionCount":1,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Validation > ### Validating CLI Arguments > #### Defining CLI Arguments via Schema > ##### CLI & Schema Incongruities\n\nThe conversion algorithm (see function `subSchemaToArgDef` in `lib/schema/cli-args.js`) is mostly\njust hacks and special cases neatly packed into a function. Things that don't cleanly map from\n`argparse` to a JSON schema include, but are not limited to:\n\n- A schema cannot natively express \"store the value of `--foo=<value>` in a property called `bar`\" in a schema (this corresponds to the `ArgumentOption['dest']` prop).\n- A schema cannot natively express aliases; e.g., `--verbose` can also be `-v`\n- A schema `enum` is not restricted to multiple types, but `argparse`'s equivalent `ArgumentOption['choices']` prop _is_\n- A schema does not know about `argparse`'s concept of \"actions\" (note that Appium is not currently using custom actions--though it did, and it could again).\n- `argparse` has no native type for `email`, `hostname`, `ipv4`, `uri` etc., and the schema does\n- Schema validation only _validates_, it does not perform translation, transformation, or coercion (mostly). `argparse` allows this.\n- Schemas allow the `null` type, for whatever reason. Ever pass `null` on the CLI?\n- `argparse` does not understand anything other than primitives; no objects, arrays, etc., and certainly not arrays of a particular type.\n\nAll of the above cases and others are handled by the adapter.\n\n!!! warning\n\n Some decisions made in the adapter were arrived at via coin toss. If you are curious about why\n something is the way it is, it's likely that it had to do _something_.\n\nLet's look more closely at handling types.","metadata":{"headerPath":"## Validation > ### Validating CLI Arguments > #### Defining CLI Arguments via Schema > ##### CLI & Schema Incongruities","sectionCount":1,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Validation > ### Validating CLI Arguments > #### Argument Types via `ajv`\n\nWhile `argparse` allows consumers, via its API, to define the _type_ of various arguments (e.g.,\na string, number, boolean flag, etc.), Appium mostly avoids these built-in types. _Why is that?_\nWell:\n\n1. We already know the type of an argument, because we've defined it in a schema.\n2. `ajv` provides validation against a schema.\n3. A schema allows for greater expression of types, allowed values, etc., than `argparse` can provide natively.\n4. The expressiveness of a schema allows for better error messaging.\n\nTo that end, the adapter eschews `argparse`'s built-in types (see allowed string values of\n`ArgumentOption['type']`) and instead abuses the ability to provide a _function_ as a `type`. The\nexception is _boolean_ flags, which do not have a `type`, but rather `action: 'store_true'`. The\nworld may never know why.\n\n## Validation > ### Validating CLI Arguments > #### Argument Types via `ajv` > ##### Types as Functions\n\nWhen a `type` is a function, the function performs both validation _and_ coercion (if necessary).\nSo what are these functions?\n\n> Note: `type` is _omitted_ (and thus _not_ a function) from the `ArgumentOption` if the property\n> type is `boolean`, and is instead provided an `action` property of `store_true`. Yes, this is\n> weird. No, I don't know why.\n\nWell... it depends upon the schema. But generally speaking, we create a _pipeline_ of functions,\neach corresponding to a keyword in the schema. Let's take the example of the `port` argument. In\nlieu of asking the OS which ports the `appium`-running user can bind to, this argument is expected\nto be an integer between 1 and 65535. This turns out to be two functions which we combine into\na pipeline:\n\n1. Convert the value to an integer, if possible. Because _every value in `process.argv` is a string_, we must coerce if we want a number.\n2. Use `ajv` to validate the integer against the schema for `port`. A schema lets us define a range via the `minimum` and `maximum` keywords. Read more about how this works in\n\nMuch like the config file validation, if errors are detected, Appium nicely tells the end-user and\nthe process exits w/ some help text.\n\nFor other arguments which are naturally of non-primitive types, things are not so straightforward.","metadata":{"headerPath":"## Validation > ### Validating CLI Arguments > #### Argument Types via `ajv`","sectionCount":2,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Validation > ### Validating CLI Arguments > #### Argument Types via `ajv` > ##### Transformers\n\nRemember how `argparse` doesn't understand arrays? What if the most ergonomic way to express\na value is, in fact, an array?\n\nWell, Appium can't accept an array on the CLI, even though it can accept one in the config file.\nBut Appium _can_ accept a comma-delimited string (a CSV \"line\"). Or a string filepath referring to\na file which _contains_ a delimited list. Either way: by the time the value gets out of the\nargument parser, it should be an array.\n\nAnd as mentioned above, the native facilities of a JSON schema cannot express this. However, it's\npossible to define a _custom keyword_ which Appium can then detect and handle accordingly. So\nthat's what Appium does.\n\nIn this case, a custom keyword `appiumCliTransformer` is registered with `ajv`. The value of\n`appiumCliTransformer` (at the time of this writing) can be `csv` or `json`. In the base schema\nfile, `appium-config-schema.js`, Appium uses `appiumCliTransformer: 'csv'` if this behavior is\ndesired.\n\n!!! note\n\n Any property defined in the schema having type `array` will _automatically_ uses the `csv`\n transformer. Likewise, a property having type `object` will use the `json` transformer. It's\n conceivable that `array` may want to use the `json` transformer, but otherwise, the presence of\n the `appiumCliTransformer` keyword on an `array`-or-`object`-typed property is not strictly\n necessary.\n\nThe adapter (remember the adapter?) creates a pipeline function including a special \"CSV\ntransformer\" (transformers are defined in `lib/schema/cli-transformers.js`), and uses this function\nas the `type` property of the `ArgumentOption` passed into `argparse`. In this case, the `type:\n'array'` in the schema is ignored.\n\n!!! note\n\n The config file doesn't _need_ to perform any complex transformation of values, because it\n naturally allows Appium to define exactly what it expects. So Appium does no post-processing of\n config file values.\n\nProperties that do not need this special treatment use `ajv` directly for validation. How this\nworks requires some explanation, so that's next.","metadata":{"headerPath":"## Validation > ### Validating CLI Arguments > #### Argument Types via `ajv` > ##### Transformers","sectionCount":1,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Validation > ### Validating CLI Arguments > #### Validation of Individual Arguments via `ajv`\n\nWhen we think of a JSON schema, we tend to think, \"I have this JSON file and I want to validate it\nagainst the schema\". That's valid, and in fact Appium does just that with config files! However,\nAppium does not do this when validating arguments.\n\n!!! note\n\n During implementation, I was tempted to mash all of the arguments together into\n a config-file-like data structure and then validate it all at once. I think that would have\n been _possible_, but since an object full of CLI arguments is a flat key/value structure and\n the schema is not, this seemed like trouble.\n\nInstead, Appium validates a value against a specific property _within_ the schema. To do this, it\nmaintains a mapping between a CLI argument definition and its corresponding property. The mapping\nitself is a `Map` with a unique identifier for the argument as the key, and an `ArgSpec`\n(`lib/schema/arg-spec.js`) object as the value.\n\nAn `ArgSpec` object stores the following metadata:\n\n| Property Name | Description |\n| --------------- | ------------------------------------------------------------------------------------- |\n| `name` | Canonical name of the argument, corresponding to the property name in the schema. |\n| `extType?` | `driver` or `plugin`, if appropriate |\n| `extName?` | Extension name, if appropriate |\n| `ref` | Computed `$id` of the property in the schema |\n| `arg` | Argument as accepted on CLI, without leading dashes |\n| `dest` | Property name in parsed arguments object (as returned by `argparse`'s `parse_args()`) |\n| `defaultValue?` | Value of the `default` keyword in schema, if appropriate |\n\nWhen a schema is [finalized](#schema-loading), the `Map` is populated with `ArgSpec` objects\nfor all known arguments.","metadata":{"headerPath":"## Validation > ### Validating CLI Arguments > #### Validation of Individual Arguments via `ajv`","sectionCount":1,"recursiveSplit":true,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Validation > ### Validating CLI Arguments > #### Validation of Individual Arguments via `ajv`\n\nWhen a schema is [finalized](#schema-loading), the `Map` is populated with `ArgSpec` objects\nfor all known arguments.\n\nSo when the adapter is creating the pipeline of functions for the argument's `type`, it already has\nan `ArgSpec` for the argument. It creates a function which calls `validate(value, ref)` (in\n`lib/schema/schema.js`) where `value` is whatever the user provided, and `ref` is the `ref`\nproperty of the `ArgSpec`. The concept is that `ajv` can validate using _any_ `ref` it knows about;\neach property in a schema can be referenced by this `ref` whether it's defined or not. To help\nvisualize, if a schema is:\n\n```json\n{\n \"$id\": \"my-schema.json\",\n \"type\": \"object\",\n \"properties\": {\n \"foo\": {\n \"type\": \"number\"\n }\n }\n}\n```\n\nThe `ref` of `foo` would be `my-schema.json#/properties/foo`. Assuming our `Ajv` instance knows\nabout this `my-schema.json`, then we can call its `getSchema(ref)` method (which has a `schema`\nproperty, but is a misnomer nonetheless) to get a validation function; `validate(value, ref)` in\n`schema.js` calls this validation function.\n\n!!! note\n\n The schema spec says a schema author can supply an explicit `$id` keyword to override this;\n it's unsupported by Appium at this time. If needed, extension authors must carefully use `$ref`\n without custom `$id`s. It's highly unlikely an extension would have a schema so complicated as\n to need this, however; Appium itself doesn't even use `$ref` to define its own properties!\n\nNext, let's take a look at how Appium loads schemas. This actually happens _before_ any argument\nvalidation.","metadata":{"headerPath":"## Validation > ### Validating CLI Arguments > #### Validation of Individual Arguments via `ajv`","sectionCount":1,"recursiveSplit":true,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Schema Loading\n\nLet's ignore extensions for a moment, and start with the base schema.\n\nWhen something first imports the `lib/schema/schema.js` module, an instance of an `AppiumSchema` is\ncreated. This is a singleton, and its methods are exported from the module (all of which are bound\nto the instance).\n\nThe constructor does very little; it instantiates an `Ajv` instance and configures it with Appium's\n[custom keywords](#custom-keyword-reference) and adds support for the `format` keyword via the\n[ajv-formats](https://npm.im/ajv-formats) module.\n\nOtherwise, the `AppiumSchema` instance does not interact with the `Ajv` instance until its\n`finalize()` method (exported as `finalizeSchema()`) is called. When this method is called, we're\nsaying \"we are not going to add any more schemas; go ahead and create `ArgSpec` objects and\nregister schemas with `ajv`\".\n\nWhen does finalization happen? Well:\n\n1. When the `appium` executable begins, it _checks for and configures extensions_ (hand-wave) in `APPIUM_HOME`.\n2. Only then does it start to think about arguments--it instantiates an `ArgParser`, which (as you'll recall) runs the adapter to convert the schema to arguments.\n3. _Finalization happens here_--when creating the parser. Appium need the schema(s) to be registered with `ajv` in order to create validation functions for arguments.\n4. Thereafter, Appium parses the arguments with the `ArgParser`.\n5. Finally, decides what to do with the returned object.\n\nWithout extensions, `finalize()` still knows about the Appium base schema\n(`appium-config-schema.js`), and just registers that. However, step 1. above is doing a _lot of\nwork_, so let's look at how extensions come into play.","metadata":{"headerPath":"## Schema Loading","sectionCount":1,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Extension Support\n\nOne of the design goals of this system is the following:\n\n_An extension should be able to register custom CLI arguments with the Appium, and a user should be\nable to use them like any other argument_.\n\nPreviously, Appium accepted arguments in this manner (via `--driverArgs`), but validation was\nhand-rolled and required extension implementors to use a custom API. It also required the user to\nawkwardly pass a JSON string as the configuration on the command-line. Further, no contextual help\n(via `--help`) existed for these arguments.\n\nNow, by providing a schema for its options, a driver or plugin can register CLI arguments and\nconfig file schemas with Appium.\n\nTo register a schema, an extension must provide the `appium.schema` property in its `package.json`.\nThe value may be a schema or a path to a schema. If the latter, the schema should be JSON or\na CommonJS module (ESM not supported at this time, nor is YAML).\n\nFor any property in this schema, the property will appear as a CLI argument of the form\n`--<extension-type>-<extension-name>-<property-name>`. For example, if the `fake` driver provides\na property `foo`, the argument will be `--driver-fake-foo`, and will show in `appium server --help`\nlike any other CLI argument.\n\nThe corresponding property in a config file would be\n`server.<extension-type>.<extension-name>.<property-name>`, e.g.:\n\n```json\n{\n \"server\": {\n \"driver\": {\n \"fake\": {\n \"foo\": \"bar\"\n }\n }\n }\n}\n```\n\nThe naming convention described above avoids problems of one extension type having a name conflict\nwith a different extension type.\n\n!!! note\n\n While an extension can provide aliases via `appiumCliAliases`, \"short\" flags are disallowed,\n since all arguments from extensions are prefixed with `--<extension-type>-<extension-name>-`.\n The extension name and argument name will be kebab-cased for the CLI, according to [Lodash's\n rules](https://lodash.com/docs/4.17.15#kebabCase) around kebab-casing.\n\nThe schema object will look much like Appium's base schema, but it will only have top-level\nproperties (nested properties are currently unsupported). Example:\n\n```json\n{\n \"title\": \"my rad schema for the cowabunga driver\",\n \"type\": \"object\",\n \"properties\": {\n \"fizz\": {\n \"type\": \"string\",\n \"default\": \"buzz\",\n \"$comment\": \"corresponds to CLI --driver-cowabunga-fizz\"\n }\n }\n}\n```\n\nAs written in a user's config file, this would be the `server.driver.cowabunga.fizz` property.","metadata":{"headerPath":"## Extension Support","sectionCount":1,"recursiveSplit":true,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Extension Support\n\nAs written in a user's config file, this would be the `server.driver.cowabunga.fizz` property.\n\nWhen extensions are loaded, the `schema` property is verified and the schema is registered with the\n`AppiumSchema` (it is _not_ registered with `Ajv` until `finalize()` is called).\n\nDuring finalization, each registered schema is added to the `Ajv` instance. The schema is assigned\nan `$id` based on the extension type and name (which overrides whatever the extension provides, if\nanything). Schemas are also forced to disallowed unknown arguments via the `additionalProperties:\nfalse` keyword.\n\nBehind the scenes, the base schema has `driver` and `plugin` properties which are objects. When\nfinalized, a property is added to each--corresponding to an extension name--and the value of this\nproperty is a reference to the `$id` of a property in the extension schema. For example, the\n`server.driver` property will look like this:\n\n```json\n{\n \"driver\": {\n \"cowabunga\": {\n \"$ref\": \"driver-cowabunga.json\"\n }\n }\n}\n```\n\nThis is why we call it the \"base\" schema--it is _mutated_ when extensions provide schemas. The\nextension schemas are kept separately, but the _references_ are added to the schema before it's\nultimately added to `ajv`. This works because an `Ajv` instance understands references _from_ any\nschema it knows about _to_ any schema it knows about.\n\n!!! note\n\n This makes it impossible to provide a complete static schema for Appium _and_ the installed\n extensions (as of Nov 5 2021). A static `.json` schema _is_ generated from the base (via a Gulp\n task), but it does not contain any extension schemas. The static schema also has uses beyond\n Appium; e.g., IDEs can provide contextual error-checking of config files this way. Let's solve\n this?\n\nJust like how we look up the reference ID of a particular argument in the base schema, validation\nof arguments from extensions happens the exact same way. If the `cowabunga` driver has the schema\nID `driver-cowabunga.json`, then the `fizz` property can be referenced from any schema registered\nwith `ajv` via `driver-cowabunga.json#/properties/fizz`. \"Base\" schema arguments begin with\n`appium.json#properties/` instead.","metadata":{"headerPath":"## Extension Support","sectionCount":1,"recursiveSplit":true,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Development Environment Support\n\nDuring the flow of development, a couple extra tasks have been automated to maintain the base\nschema:\n\n- As a post-transpilation step, a `lib/appium-config.schema.json` gets generated from\n- `lib/schema/appium-config-schema.js` (in addition to its CJS counterpart generated by Babel).\n- This file is under version control. It ends up being _copied_ to\n- `build/lib/appium-config.schema.json` in this step. A pre-commit hook (see\n- `scripts/generate-schema-declarations.js` in the root monorepo) generates\n- a `types/appium-config-schema.d.ts` from the above JSON file. The types in `types/types.d.ts`\n- depend upon this file. This file is under version control.","metadata":{"headerPath":"## Development Environment Support","sectionCount":1,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"## Custom Keyword Reference\n\nKeywords are defined in `lib/schema/keywords.js`.\n\n- `appiumCliAliases`: allows a schema to express aliases (e.g., a CLI argument can be `--verbose` or `-v`). This is an array of strings. Strings shorter than three (3) characters will begin with a single dash (`-`) instead of a double-dash (`--`). Note that any argument provided by an extension will begin with a double-dash, because these are required to have the `--<extension-type>-<extension-name>-` prefix.\n- `appiumCliDest`: allows a schema to specify a custom property name in the post-`argprase` arguments objects. If not set, this becomes a camelCased string.\n- `appiumCliDescription`: allows a schema to override the description of the argument when displayed on the command-line. This is useful paired with `appiumCliTransformer` (or `array`/`object`-typed properties), since there's a substantial difference between what a CLI-using user can provide vs. what a config-file-using user can provide.\n- `appiumCliTransformer`: currently a choice between `csv` and `json`. These are custom functions which post-process a value. They are not used when loading & validating config files, but the idea should be that they result in the same object you'd get if you used whatever the config file wanted (e.g., an array of strings). `csv` is for comma-delimited strings and CSV files; `json` is for raw JSON strings and `.json` files.\n- `appiumCliIgnore`: If `true`, do not support this property on the CLI.\n- `appiumDeprecated`: If `true`, the property is considered \"deprecated\", and will be displayed as such to the user (e.g., in the `--help` output). Note the JSON Schema draft-2019-09 introduces a new keyword `deprecated` which we should use instead if upgrading to this metaschema. When doing so, `appiumDeprecated` should itself be marked as `deprecated`.","metadata":{"headerPath":"## Custom Keyword Reference","sectionCount":1,"filename":"config-system.md","relativePath":"appium/packages/appium/docs/en/developing/config-system.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Developing Appium Extensions\n---\n\nAppium is built with a modular structure, which means that Appium extensions (drivers and plugins)\nare decoupled from the main Appium module, and you only need to install the extensions that you\nwant to use. This modular structure also unlocks the ability to develop entirely new extensions!\n\nThis section of the Appium documentation is intended to help aspiring developers with creating their\nown Appium extension:\n\n* For creating a driver, see the [Build Drivers](./build-drivers.md) page\n* For creating a plugin, take a look at the [Build Plugins](build-plugins.md) page\n* Drivers and plugins both need documentation, so check out the [Build Documentation](./build-docs.md) page\n* For creating a doctor check, see the [Building Doctor Checks](./build-doctor-checks.md) page","metadata":{"headerPath":"","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/developing/index.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Masking Sensitive Log Data\n---\n\nSince Appium server version 2.18.0 there is a possibility to mask sensitive\nvalues in logs. The below tutorial explains how to use this feature in third-party\nextensions.\n\n## Why It Might Be Useful\n\nIt is the right call to hide sensitive information, like passwords, tokens, etc.\nfrom server logs, so it does not accidentally leak if these logs end up in wrong hands.\nAppium server already provides a way to manipulate logs records via\n[filtering](../guides/log-filters.md), although it has its own limitations.\nThe current approach is more sophisticated though, and requires some fine-tuning\non the driver/plugin side.\n\n## How To\n\nThe assumption is that your extension uses the standard built-in\n[@appium/logger](https://www.npmjs.com/package/@appium/logger).\nIn order to get some value in logs replaced by a generic mask it is necessary:\n\n- Change the logging expression to wrap sensitive values and format them, for example:\n\n ```js\n this.log.info(`Value: ${value}`);\n ```\n\n becomes\n\n ```js\n import {logger} from '@appium/support';\n\n this.log.info('Value: %s', logger.markSensitive(value));\n ```\n\n The formatting happens via the standard Node.js's\n [util.format](https://nodejs.org/api/util.html#utilformatformat-args) API.\n\n- While sending the appropriate server request, where this log line is used and should be masked,\n add the custom header `X-Appium-Is-Sensitive` with its value set to `1` or `true` (case-insensitive).\n Without such header the above log value is not going to be masked.\n This way it is possible to conditionally mask log records depending on which\n request is being handled by the extension if the log expression is used in the\n common section.","metadata":{"headerPath":"","sectionCount":3,"filename":"sensitive.md","relativePath":"appium/packages/appium/docs/en/developing/sensitive.md"}},{"pageContent":"---\ntitle: Appium Clients\n---\n\nYou need a client to write and run Appium scripts. You'll want to become very\nfamiliar with your client documentation (as well as the documentation of any Selenium client that\nthe Appium client depends on) since that will be your primary interface to Appium.\n\nTo learn more about clients, check out the [Client Intro](../intro/clients.md).\n\n!!! note\n\n If you maintain an Appium client that you would like to be listed here, feel free to create a PR!\n\n## Official Clients\n\nThese clients are currently maintained by the Appium team:\n\n## Official Clients > ### [Java Client](https://github.com/appium/java-client)\n\nLanguage: :fontawesome-brands-java: Java\n\n=== \"Setup With Maven\"\n\n ```xml\n <dependency>\n <groupId>io.appium</groupId>\n <artifactId>java-client</artifactId>\n <version>${version.you.require}</version>\n <scope>test</scope>\n </dependency>\n ```\n=== \"Setup With Gradle\"\n\n ```groovy\n dependencies {\n testImplementation 'io.appium:java-client:${version.you.require}'\n }\n ```\n\n## Official Clients > ### [Python Client](https://github.com/appium/python-client)\n\nLanguage: :fontawesome-brands-python: Python\n\n```sh title=\"Install From PyPi\"\npip install Appium-Python-Client\n```\n\n## Official Clients > ### [Ruby Core Client](https://github.com/appium/ruby_lib_core)\n\nLanguage: :material-language-ruby: Ruby\n\n```sh title=\"Install From RubyGems\"\ngem install appium_lib_core\n```\n\n## Official Clients > ### [Ruby Client](https://github.com/appium/ruby_lib)\n\nLanguage: :material-language-ruby: Ruby\n\nThis client is a wrapper for the Ruby Core Client with several helper methods, though this may\nadd additional complexity, therefore the Ruby Core Client is recommended instead.\n\n```sh title=\"Install From RubyGems\"\ngem install appium_lib\n```\n\n## Official Clients > ### [.NET Client](https://github.com/appium/dotnet-client)\n\nLanguage: :simple-dotnet: C#\n\n```sh title=\"Install Using .NET CLI\"\ndotnet add package Appium.WebDriver\n```\n\n## Other Clients\n\nThese clients are not maintained by the Appium team and can be used with other languages.\n\nIn general, any W3C WebDriver spec-compatible client will also integrate well with Appium, though\nsome Appium-specific commands may not be implemented in other clients.","metadata":{"headerPath":"","sectionCount":8,"filename":"clients.md","relativePath":"appium/packages/appium/docs/en/ecosystem/clients.md"}},{"pageContent":"## Other Clients > ### [WebdriverIO](https://webdriver.io/docs/appium)\n\nLanguage: :material-language-javascript: :material-language-typescript: JavaScript/TypeScript\n\n```sh title=\"Setup Using npm\"\nnpm init wdio@latest .\n```\n\n## Other Clients > ### [Nightwatch.js](https://nightwatchjs.org/guide/mobile-app-testing/introduction.html)\n\nLanguage: :material-language-javascript: :material-language-typescript: JavaScript/TypeScript\n\n=== \"Setup For Android\"\n\n ```sh\n npx @nightwatch/mobile-helper android --appium\n ```\n\n=== \"Setup For iOS\"\n\n ```sh\n npx @nightwatch/mobile-helper ios --appium\n ```\n\n## Other Clients > ### [RobotFramework AppiumLibrary](https://github.com/serhatbolsu/robotframework-appiumlibrary)\n\nLanguage: :simple-robotframework: Robot Framework\n\n```sh title=\"Install From PyPi\"\npip install robotframework-appiumlibrary\n```\n\n## Other Clients > ### [multicatch's appium-client](https://github.com/multicatch/appium-client)\n\nLanguage: :simple-rust: Rust\n\n```sh title=\"Install Using Cargo\"\ncargo add appium-client\n```\n\n## Other Clients > ### [SwiftAppium](https://github.com/milcgroup/swiftappium)\n\nLanguage: :material-language-swift: Swift\n\n```sh title=\"Install and Setup\"\ngit clone https://github.com/milcgroup/SwiftAppium.git\ncd SwiftAppium\nswift build\nswift run swiftappium\n```","metadata":{"headerPath":"## Other Clients > ### [WebdriverIO](https://webdriver.io/docs/appium)","sectionCount":5,"filename":"clients.md","relativePath":"appium/packages/appium/docs/en/ecosystem/clients.md"}},{"pageContent":"---\ntitle: Appium Drivers\n---\n\nYou can't use Appium without a driver! Here you can find a list of all known Appium drivers,\nalong with their installation commands and links to their documentation.\n\nTo learn more about drivers, check out the [Driver Intro](../intro/drivers.md).\n\n!!! note\n\n If you maintain an Appium driver that you would like to be listed here, feel free to create a PR!\n\n## Official Drivers\n\nThese drivers are currently maintained by the Appium team:\n\n## Official Drivers > ### [Chromium](https://github.com/appium/appium-chromium-driver)\n\n* Target: Desktop and mobile Chromium browsers (Chrome, Microsoft Edge, etc.)\n* Mode: Web\n\n```sh title=\"Install This Driver\"\nappium driver install chromium\n```\n\n## Official Drivers > ### [Espresso](https://github.com/appium/appium-espresso-driver)\n\n* Target: Android applications\n* Mode: Native\n\n```sh title=\"Install This Driver\"\nappium driver install espresso\n```\n\n## Official Drivers > ### [Gecko](https://github.com/appium/appium-geckodriver)\n\n* Target: Desktop and mobile Gecko browsers (Firefox)\n* Mode: Web\n\n```sh title=\"Install This Driver\"\nappium driver install gecko\n```\n\n## Official Drivers > ### [Mac2](https://github.com/appium/appium-mac2-driver)\n\n* Target: macOS applications\n* Mode: Native\n\n```sh title=\"Install This Driver\"\nappium driver install mac2\n```\n\n## Official Drivers > ### [Safari](https://github.com/appium/appium-safari-driver)\n\n* Target: Desktop and mobile Safari browsers\n* Mode: Web\n\n```sh title=\"Install This Driver\"\nappium driver install safari\n```\n\n## Official Drivers > ### [UiAutomator2](https://github.com/appium/appium-uiautomator2-driver)\n\n* Target: Android, Android TV, Android Wear applications\n* Modes: Native, Hybrid, Web\n\n```sh title=\"Install This Driver\"\nappium driver install uiautomator2\n```\n\n## Official Drivers > ### [Windows](https://github.com/appium/appium-windows-driver)\n\n!!! warning\n\n Only the Node.js-based driver part is maintained by the Appium team. The server part\n (WinAppDriver executable) is provided by Microsoft, but has not been maintained since 2022.\n\n* Target: Windows applications\n* Mode: Native\n\n```sh title=\"Install This Driver\"\nappium driver install windows\n```\n\n## Official Drivers > ### [XCUITest](https://appium.github.io/appium-xcuitest-driver/)\n\n* Target: iOS, iPadOS, tvOS applications\n* Modes: Native, Hybrid, Web\n\n```sh title=\"Install This Driver\"\nappium driver install xcuitest\n```","metadata":{"headerPath":"","sectionCount":10,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/ecosystem/drivers.md"}},{"pageContent":"## Other Drivers\n\nThese drivers are not maintained by the Appium team and can be used to target other platforms:\n\n## Other Drivers > ### [Flutter](https://github.com/appium/appium-flutter-driver)\n\n* Target: iOS and Android applications built with Flutter\n* Mode: Native\n* Supported by: Appium Team / Community\n\n```sh title=\"Install This Driver\"\nappium driver install --source=npm appium-flutter-driver\n```\n\n## Other Drivers > ### [Flutter Integration](https://github.com/AppiumTestDistribution/appium-flutter-integration-driver)\n\n* Target: iOS and Android applications built with Flutter\n* Mode: Native\n* Supported by: Community / `@AppiumTestDistribution`\n\n```sh title=\"Install This Driver\"\nappium driver install --source=npm appium-flutter-integration-driver\n```\n\n## Other Drivers > ### [LG WebOS](https://github.com/headspinio/appium-lg-webos-driver)\n\n* Target: LG TV web applications\n* Mode: Web\n* Supported by: HeadSpin\n\n```sh title=\"Install This Driver\"\nappium driver install --source=npm appium-lg-webos-driver\n```\n\n## Other Drivers > ### [Linux](https://github.com/fantonglang/appium-linux-driver)\n\n!!! warning\n\n This driver has not been maintained since 2022 and requires a custom Appium installation\n\n* Target: Linux applications\n* Mode: Native\n* Supported by: `@fantonglang`\n\n```sh title=\"Install This Driver\"\ngit clone https://github.com/fantonglang/appium\ncd appium\nyarn install\nnode ./\n```\n\n## Other Drivers > ### [NovaWindows](https://github.com/AutomateThePlanet/appium-novawindows-driver)\n\n!!! info\n\n This driver is recommended as a drop-in replacement for the partially unmaintained\n [Windows driver](#windows)\n\n* Target: Windows applications\n* Mode: Native\n* Supported by: Community / Automate The Planet\n\n```sh title=\"Install This Driver\"\nappium driver install --source=npm appium-novawindows-driver\n```\n\n## Other Drivers > ### [Roku](https://github.com/headspinio/appium-roku-driver)\n\n* Target: Roku channels (applications)\n* Mode: Native\n* Supported by: HeadSpin\n\n```sh title=\"Install This Driver\"\nappium driver install --source=npm @headspinio/appium-roku-driver\n```\n\n## Other Drivers > ### [Tizen](https://github.com/Samsung/appium-tizen-driver)\n\n!!! warning\n\n This driver has not been maintained since 2020 and is only compatible with Appium 1\n\n* Target: Tizen applications\n* Mode: Native\n* Supported by: Community / Samsung\n\n```sh title=\"Install This Driver\"\nnpm install appium-tizen-driver\n```","metadata":{"headerPath":"## Other Drivers","sectionCount":8,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/ecosystem/drivers.md"}},{"pageContent":"## Other Drivers > ### [TizenTV](https://github.com/headspinio/appium-tizen-tv-driver)\n\n* Target: Tizen TV web applications\n* Mode: Web\n* Supported by: HeadSpin\n\n```sh title=\"Install This Driver\"\nappium driver install --source=npm appium-tizen-tv-driver\n```\n\n## Other Drivers > ### [You.i Engine](https://github.com/YOU-i-Labs/appium-youiengine-driver)\n\n!!! warning\n\n This driver has not been maintained since 2022 and is only compatible with Appium 1\n\n* Target: iOS, Android, macOS, Linux, tvOS applications built with You.i Engine\n* Mode: Native\n* Supported by: Community / You.i\n\n```sh title=\"Install This Driver\"\nnpm install appium-youiengine-driver\n```","metadata":{"headerPath":"## Other Drivers > ### [TizenTV](https://github.com/headspinio/appium-tizen-tv-driver)","sectionCount":2,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/ecosystem/drivers.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: The Appium Ecosystem\n---\n\nAppium has a wide ecosystem of related software and tools. This section of the Appium documentation\naims to compile a listing of various officially-supported and community-supported Appium projects:\n\n<div class=\"grid cards\" markdown>\n\n- :material-car: __Drivers__\n\n ---\n\n Link Appium to your test device\n\n [:octicons-arrow-right-24: View all drivers](./drivers.md)\n\n- :octicons-code-16: __Clients__\n\n ---\n\n Link Appium to your automation code\n\n [:octicons-arrow-right-24: View all clients](./clients.md)\n\n- :fontawesome-solid-plug: __Plugins__\n\n ---\n\n Modify and extend Appium functionality\n\n [:octicons-arrow-right-24: View all plugins](./plugins.md)\n\n- :material-wrench: __Tools__\n\n ---\n\n Interact with Appium in other ways\n\n [:octicons-arrow-right-24: View all tools](./tools.md)\n\n</div>","metadata":{"headerPath":"","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/ecosystem/index.md"}},{"pageContent":"---\ntitle: Appium Plugins\n---\n\nPlugins offer various ways to extend or modify Appium's behaviour. They are _completely optional_\nand are not needed for standard automation functionality, but you may find them to be useful\nfor more specialised automation workflows.\n\n!!! note\n\n If you maintain an Appium plugin that you would like to be listed here, feel free to create a PR!\n\n## Official Plugins\n\nThese plugins are are currently maintained by the Appium team:\n\n## Official Plugins > ### [Execute Driver](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin)\n\nRun entire batches of commands in a single call to the Appium server\n\n```sh title=\"Install This Plugin\"\nappium plugin install execute-driver\n```\n\n## Official Plugins > ### [Images](https://github.com/appium/appium/tree/master/packages/images-plugin)\n\nAdd support for image matching and comparison features\n\n```sh title=\"Install This Plugin\"\nappium plugin install images\n```\n\n## Official Plugins > ### [Inspector](https://github.com/appium/appium-inspector/tree/main/plugins)\n\nIntegrate the [Appium Inspector](https://appium.github.io/appium-inspector/) directly into your\nAppium server installation\n\n```sh title=\"Install This Plugin\"\nappium plugin install inspector\n```\n\n## Official Plugins > ### [Relaxed Caps](https://github.com/appium/appium/tree/master/packages/relaxed-caps-plugin)\n\nRelax Appium's requirement for vendor prefixes on capabilities\n\n```sh title=\"Install This Plugin\"\nappium plugin install relaxed-caps\n```\n\n## Official Plugins > ### [Storage](https://github.com/appium/appium/tree/master/packages/storage-plugin)\n\nAdd server-side storage with client-side management\n\n```sh title=\"Install This Plugin\"\nappium plugin install storage\n```\n\n## Official Plugins > ### [Universal XML](https://github.com/appium/appium/tree/master/packages/universal-xml-plugin)\n\nTranslate the default iOS and Android XML formats into a common format\n\n```sh title=\"Install This Plugin\"\nappium plugin install universal-xml\n```\n\n## Other Plugins\n\nThese plugins are not maintained by the Appium team and can provide additional functionality:\n\n## Other Plugins > ### [AltUnity](https://github.com/headspinio/appium-altunity-plugin)\n\nTarget Unity games and apps for automation via the AltUnityTester framework\n\nSupported by: HeadSpin\n\n```sh title=\"Install This Plugin\"\nappium plugin install --source=npm appium-altunity-plugin\n```","metadata":{"headerPath":"","sectionCount":10,"filename":"plugins.md","relativePath":"appium/packages/appium/docs/en/ecosystem/plugins.md"}},{"pageContent":"## Other Plugins > ### [Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)\n\nManage and create driver sessions on connected Android devices and iOS simulators\n\nSupported by: `@AppiumTestDistribution`\n\n```sh title=\"Install This Plugin\"\nappium plugin install --source=npm appium-device-farm\n```\n\n## Other Plugins > ### [Gestures](https://github.com/AppiumTestDistribution/appium-gestures-plugin)\n\nPerform basic gestures using W3C Actions\n\nSupported by: `@AppiumTestDistribution`\n\n```sh title=\"Install This Plugin\"\nappium plugin install --source=npm appium-gestures-plugin\n```\n\n## Other Plugins > ### [Interceptor](https://github.com/AppiumTestDistribution/appium-interceptor-plugin)\n\nIntercept and mock API requests and responses\n\nSupported by: `@AppiumTestDistribution`\n\n```sh title=\"Install This Plugin\"\nappium plugin install --source=npm appium-interceptor\n```\n\n## Other Plugins > ### [OCR](https://github.com/jlipps/appium-ocr-plugin)\n\nFind elements via OCR text\n\nSupported by: `@jlipps`\n\n```sh title=\"Install This Plugin\"\nappium plugin install --source=npm appium-ocr-plugin\n```\n\n## Other Plugins > ### [Reporter](https://github.com/AppiumTestDistribution/appium-reporter-plugin)\n\nGenerate standalone consolidated HTML reports with screenshots\n\nSupported by: `@AppiumTestDistribution`\n\n```sh title=\"Install This Plugin\"\nappium plugin install --source=npm appium-reporter-plugin\n```\n\n## Other Plugins > ### [Wait](https://github.com/AppiumTestDistribution/appium-wait-plugin)\n\nManage global element wait timeouts\n\nSupported by: `@AppiumTestDistribution`\n\n```sh title=\"Install This Plugin\"\nappium plugin install --source=npm appium-wait-plugin\n```","metadata":{"headerPath":"## Other Plugins > ### [Device Farm](https://github.com/AppiumTestDistribution/appium-device-farm)","sectionCount":6,"filename":"plugins.md","relativePath":"appium/packages/appium/docs/en/ecosystem/plugins.md"}},{"pageContent":"---\ntitle: Appium-Related Tools\n---\n\nThe Appium ecosystem also includes several tools that have been created to assist with things not\ndirectly related to running tests, such as Appium installation, test development, and more.\n\n!!! note\n\n If you maintain an Appium tool that you would like to be listed here, feel free to create a PR!\n\n## Official Tools\n\nThese tools are currently maintained by the Appium team:\n\n## Official Tools > ### [Appium Inspector](https://appium.github.io/appium-inspector/)\n\nAppium has a graphical client which can be used to inspect application screenshots, view the\napplication hierarchy, search for elements, run Appium commands, record app interactions, and more.\nIt can be very useful for Appium test development.\n\n## Extension Tools\n\nAppium driver or plugin developers can choose to include these tools in their driver/plugin:\n\n## Extension Tools > ### Appium Doctor\n\nThe Appium Doctor tool can be used to validate whether all prerequisites and other environment\ndetails needed for the driver/plugin have been set up correctly. The tool can be accessed via the\n[`doctor` command in the Appium CLI](../reference/cli/extensions.md#doctor):\n\n```sh\nappium {driver|plugin} doctor <extension-name>\n```\n\nIt shows no results if the driver/plugin author did not implement Doctor support.\n\n!!! note\n\n If you maintain an Appium extension and would like to add Appium Doctor support for it, check\n out the documentation on [Building Doctor Checks](../developing/build-doctor-checks.md).\n\n## Other Tools\n\nThese tools are not maintained by the Appium team:\n\n## Other Tools > ### [Appium Installer](https://github.com/AppiumTestDistribution/appium-installer)\n\nAppium Installer is a command-line tool for simplifying setups of new Appium test environments.\nIt includes commands for installing Appium, its drivers and plugins, as well as validating\nprerequisites for iOS or Android emulators or real devices.\n\nSupported by: `@AppiumTestDistribution`\n\n```sh title=\"Install This Tool\"\nnpm install -g appium-installer\n```","metadata":{"headerPath":"","sectionCount":7,"filename":"tools.md","relativePath":"appium/packages/appium/docs/en/ecosystem/tools.md"}},{"pageContent":"## Other Tools > ### [Jarvis Appium](https://github.com/AppiumTestDistribution/mcp-appium)\n\nJarvis Appium is a Model Context Protocol (MCP) server that provides mobile test development and\nautomation capabilities using Appium.\n\nSupported by: `@AppiumTestDistribution`\n\n```json title=\"Install This Tool\"\n// Add the following to your MCP client configuration\n{\n \"mcpServers\": {\n \"jarvis-appium\": {\n \"disabled\": false,\n \"timeout\": 100,\n \"type\": \"stdio\",\n \"command\": \"npx\",\n \"args\": [\"jarvis-appium\"],\n \"env\": {\n \"ANDROID_HOME\": \"/path/to/android/sdk\",\n \"CAPABILITIES_CONFIG\": \"/path/to/your/capabilities.json\"\n }\n }\n }\n}\n```","metadata":{"headerPath":"## Other Tools > ### [Jarvis Appium](https://github.com/AppiumTestDistribution/mcp-appium)","sectionCount":1,"filename":"tools.md","relativePath":"appium/packages/appium/docs/en/ecosystem/tools.md"}},{"pageContent":"---\ntitle: Local Validation Of Extension PRs\n---\n\nSometimes it might be necessary to validate if a remote driver or a plugin PR works for the particular local\nenvironment before it is merged or published. This tutorial describes how to achieve that.\n\n## Requirements\n\n- Recent LTS version of NodeJS. Check [Node.js main page](https://nodejs.org) for the download link.\n- Recent version of the Appium server. Use the following commands to ensure you have\n the latest version installed: `npm uninstall appium` and `npm install -g appium`.\n- [Git](https://git-scm.com/) should be available locally.","metadata":{"headerPath":"","sectionCount":2,"filename":"branch-testing.md","relativePath":"appium/packages/appium/docs/en/guides/branch-testing.md"}},{"pageContent":"## Installation\n\n- [Check out](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally) the PR locally.\n There is also an option (although it is less flexible, because you won't be able to easily fetch\n any changes to this PR later) to simply [download](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives) and unzip the sources\n locally. If you choose the later option then no `git` tool would be necessary.\n- Navigate to the local driver or plugin folder and run `npm i` from that folder.\n- Make sure you don't have the given driver or plugin already installed. Use the `appium driver uninstall <driver_name>`\n or `appium plugin uninstall <plugin_name>` CLI in order to delete any leftovers. The value of\n `<driver_name>`/`<plugin_name>` depends on the actual driver or plugin name the PR has been prepared for.\n If you are not sure which name you need to use then check the content of the `package.json` manifest,\n which must be always located under the root folder of the fetched sources. You should be looking for\n the `\"appium\" -> \"driverName\"` entry value there.\n- Change the current folder to the one, which is NOT the driver/plugin folder root or its subfolder.\n Also, make sure your current working folder does not contain any extra `package.json` file. If\n it does then simply navigate to any other folder that does not.\n- Run the following command in order to link the driver/plugin sources to the Appium server:\n `appium driver install --source=local <full_path_to_driver_folder_with_fetched_sources>` or\n `appium plugin install --source=local <full_path_to_plugin_folder_with_fetched_sources>`.\n- Stop the Appium server if it is running and start it again (`appium server --use-drivers=<driver_name>`)\n to check the list of loaded drivers. If the linking succeeded then you must see the driver name and the path to its\n parent folder in the server logs. In case of a plugin it is required to explicitly request\n this plugin to be loaded upon server startup: `appium server --use-plugins=<plugin_name>`.","metadata":{"headerPath":"## Installation","sectionCount":1,"filename":"branch-testing.md","relativePath":"appium/packages/appium/docs/en/guides/branch-testing.md"}},{"pageContent":"## Update\n\nAfter you have tested the PR and there are issues it might be necessary to update the local branch with\nthe recent changes from Git. Follow the next steps for that:\n\n- Navigate to the parent folder of your local driver/plugin and run `git pull`.\n- Stop Appium server if it is running.\n- Run `npm i` in the parent folder of your local driver/plugin to rebuild it and update any dependencies if necessary.\n- Start Appium server again similarly to how this is done in the corresponding [Installation](#installation) step above.\n\n## Switching Back To a Stable Release\n\nAfter the PR is merged there is no need to use the local plugin/driver deployment anymore, and it makes sense\nto switch back to the package managed by NPM. Follow the next steps for that:\n\n- Unlink the installed driver/plugin from the server by running `appium driver uninstall <driver_name>` or\n `appium plugin uninstall <driver_name>`.\n- Delete the local source folder (`rm -rf <full_path_to_plugin_or_driver_folder_with_fetched_sources>`).\n- Install the driver or the plugin from NPM. Check the component README in order to find a proper command for that.","metadata":{"headerPath":"## Update","sectionCount":2,"filename":"branch-testing.md","relativePath":"appium/packages/appium/docs/en/guides/branch-testing.md"}},{"pageContent":"---\ntitle: Caching of Application Bundles\n---\n\nAppium's base driver provides a feature which enables caching of application builds provided, for example,\nas `app` capability value or to endpoints similar to the `installApp` one. This article explains common caching\nprinciples, so you could create more performant and efficient test suite execution strategies.\n\n## Why Caching Is Necessary\n\nMobile application bundles could reach hundreds of megabytes is size. This could become a serious\nperformance issue if a test suite is executed, and it is necessary to fetch/extract the same application\nbundle for each test.\n\n## What Is Cached\n\nCaching could be applied to application bundles generated by\n[`configureApp`](https://github.com/appium/appium/blob/master/packages/base-driver/lib/basedriver/helpers.js#L107) helper call.\nInherited drivers can customize their caching logic by providing own `onPostProcess`\n(or both `inDownload` and `onPostProcess`) property definition, but the general\nrule of thumb is that we need to cache locally all application bundles need to be downloaded and/or extracted\nfirst before they could be actually installed on the device under test. On iOS, for example, these are `.ipa` or\n`.zip` compressed application bundles, or .`aab` on Android.\n\n## Caching of Remote Application Bundles\n\nIn order to validate whether an app bundle downloaded from the given URL could be (re)used from the cache the following\nsteps are applied:\n\n1. The script checks if the given URL is already present in the cache.\n If yes then it tries to fetch previously remembered\n [Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified)\n or [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) header values for it.\n2. If `ETag` value is present then it is put into\n [If-None-Match request header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match).\n Else if `Last-Modified` header value is present then it is put into\n [If-Modified-Since request header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since).\n Otherwise, no caching is applied.\n3. If the response status is equal to `304` then the previously cached binary is used,\n otherwise the cached entry is reset and refreshed.","metadata":{"headerPath":"","sectionCount":4,"filename":"caching.md","relativePath":"appium/packages/appium/docs/en/guides/caching.md"}},{"pageContent":"## Caching of Local Application Bundles\n\nIt only makes sense to cache application bundles if they need some preprocessing before being installed on the device under test.\nFor example, on iOS `.ipa` bundles must be unzipped, because the system installer only works with `.app` folders.\n\n1. The script verifies if the given bundle path is already present in the cache. If the bundle was not in the cache yet\nthen it gets preprocessed and added there.\n2. The script validates the hashsum of the bundle and compares it to the previously stored one. If hash sums don't match\nthen the cached item gets deleted and the preprocessing of the bundle repeats.\n\n## How The Cache File System Is Configured\n\nThe cache where the base driver keeps all application bundles is located in the system temp folder. It is configured\non per-process basis, so each test session initialized in scope of the same Appium server process takes advantages\nof it. It is a [LRU Cache](https://www.npmjs.com/package/lru-cache) with the following limitations:\n\n- Max items: 1024. You may customize it by providing a new value to\n the [APPIUM_APPS_CACHE_MAX_ITEMS](../reference/cli/env-vars.md) environment variable.\n Do not set it to a lower number than the amount of apps in all parallel sessions per process.\n- Max time to live (TTL) for each entry: 24 hours.\n You may customize it by providing a new value to the\n [APPIUM_APPS_CACHE_MAX_AGE](../reference/cli/env-vars.md) environment variable.\n Do not set it to a lower number than the duration of a single session startup.\n- TTL is refreshed for each entry upon access\n- By default the full application URL is used as cache key. You may change this behavior\n by enabling the [APPIUM_APPS_CACHE_IGNORE_URL_QUERY](../reference/cli/env-vars.md) environment variable.\n If the above option is enabled then the 'search' part of the app URL will be cut off from cache keys.\n See the corresponding [feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713)\n for more details.\n\n!!! warning\n\n Note: The cache root folder is set up for automatic deletion on Appium process termination. This would only\n work if Appium server is killed with `SIGINT` or `SIGTERM`. If `SIGKILL` is used then no cache cleanup\n would be performed.","metadata":{"headerPath":"## Caching of Local Application Bundles","sectionCount":2,"filename":"caching.md","relativePath":"appium/packages/appium/docs/en/guides/caching.md"}},{"pageContent":"---\ntitle: Session Capabilities\n---\n\n\"Capabilities\" is the name given to the set of parameters used to start an Appium session. The\ninformation in the set describes what sort of \"capabilities\" you want your session to have, for\nexample, a certain mobile operating system or a certain version of a device. Capabilities are\nrepresented as key-value pairs, with values allowed to be any valid JSON type, including\nother objects.\n\nThe W3C WebDriver spec's [section on Capabilities](https://w3c.github.io/webdriver/#capabilities)\nidentifies a small set of 10 standard capabilities, including the following:\n\n| Capability Name | Type | Description |\n|------------------|----------|------------------------------------------------|\n| `browserName` | `string` | The name of the browser to launch and automate |\n| `browserVersion` | `string` | The specific version of the browser |\n| `platformName` | `string` | The type of platform hosting the browser |","metadata":{"headerPath":"","sectionCount":1,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## Common Appium Capabilities\n\nAppium understands these browser-focused capabilities, but introduces a number of additional\ncapabilities. According to the WebDriver spec, any\nnon-standard \"extension capabilities\" must include a namespace prefix (signifying the vendor\nintroducing the capability), ending in a `:`. Appium's vendor prefix is\n`appium:`, and so any Appium-specific capabilities must include this prefix. Depending on which\nclient you are using, the prefix may be added automatically or in conjunction with certain\ninterfaces, but it is always a good practice to explicitly include it for clarity.\n\nHere is a list of all the globally-recognized Appium capabilities:\n\n!!! info\n\n Individual drivers and plugins can support other capabilities, so refer to their documentation\n for lists of specific capability names. Some drivers may also not support all of these capabilities","metadata":{"headerPath":"## Common Appium Capabilities","sectionCount":1,"recursiveSplit":true,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## Common Appium Capabilities\n\n| <div style=\"width:12em\">Capability</div> | Type | Required? | Description |\n|--------------------------------------------|-----------|-----------|----------------------------|\n| `platformName` | `string` | yes | The type of platform hosting the app or browser |\n| `appium:automationName` | `string` | yes | The name of the Appium driver to use |\n| `browserName` | `string` | no | The name of the browser to launch and automate, if the driver supports web browsers as a special case |\n| `appium:app` | `string` | no | The path to an installable application |\n| `appium:deviceName` | `string` | no | The name of a particular device to automate, e.g., `iPhone 14` (currently only actually useful for specifying iOS simulators, since in other situations it's typically recommended to use a specific device id via the `appium:udid` capability). |\n| `appium:platformVersion` | `string` | no | The version of a platform, e.g., for iOS, `16.0` |\n| `appium:newCommandTimeout` | `number` | no | The number of seconds the Appium server should wait for clients to send commands before deciding that the client has gone away and the session should shut down. `60` seconds by default. Setting it to zero disables the timer. |\n| `appium:noReset` | `boolean` | no | If true, instruct an Appium driver to avoid its usual reset logic during session start and cleanup (default `false`) |\n| `appium:fullReset` | `boolean` | no | If true, instruct an Appium driver to augment its usual reset logic with additional steps to ensure maximum environmental reproducibility (default `false`) |\n| `appium:eventTimings` | `boolean` | no | If true, instruct an Appium driver to collect [Event Timings](./event-timing.md) (default `false`) |\n| `appium:printPageSourceOnFindFailure` | `boolean` | no | If true, collect the page source and print it to the Appium log whenever a request to find an element fails (default `false`) |","metadata":{"headerPath":"## Common Appium Capabilities","sectionCount":1,"recursiveSplit":true,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## Common Appium Capabilities\n\nSome drivers place more complex constraints on capabilities as a group. For example, while the\n`appium:app` and `browserName` capabilities are listed above as optional, if you want to launch\na session with a specific app, the XCUITest driver requires that at least one of `appium:app`,\n`browserName`, or `appium:bundleId` are included in the capabilities (otherwise it will not know\nwhat app to install and/or launch and will simply open a session on the home screen). Each driver\nwill document how it interprets these capabilities and any other platform-specific requirements.\n\n!!! note\n\n Capabilities are like parameters used when starting a session. After the capabilities are sent\n and the session is started, they cannot be changed. If a driver supports updating aspects of\n its behaviour in the course of a session, it will provide a [Setting](./settings.md) for this\n purpose instead of, or in addition to, a capability.\n\nEach Appium client has its own way of constructing capabilities and starting a session. For\nexamples of doing this in each client library, head to the [Ecosystem](../ecosystem/index.md) page\nand click through to the appropriate client documentation.","metadata":{"headerPath":"## Common Appium Capabilities","sectionCount":1,"recursiveSplit":true,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## BiDi Protocol Support\n\nAppium supports [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) protocol since base–driver 9.5.0.\nThe actual behavior depends on individual drivers while the Appium and the baseーdriver support the protocol.\nPlease make sure if a driver supports the protocol and what kind of commands/events it supports in the documentation.\n\n| Capability Name | Type | Description |\n|-----------------|-----------|-----------------------------------------|\n| `webSocketUrl` | `boolean` | To enable BiDi protocol in the session. |\n\n## Using `appium:options` to Group Capabilities\n\nIf you use a lot of `appium:` capabilities in your tests, it can get a little repetitive. You can\ncombine all capabilities as an object value of a single `appium:options` capability instead, in\nwhich case you don't need to use prefixes on the capabilities inside the object. For example:\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:options\": {\n \"automationName\": \"XCUITest\",\n \"platformVersion\": \"16.0\",\n \"app\": \"/path/to/your.app\",\n \"deviceName\": \"iPhone 12\",\n \"noReset\": true\n }\n}\n```\n\nNote that constructing a capability value which is itself an object differs by language; refer to\nyour client documentation for further examples on how to achieve this.\n\n!!! warning\n\n If you include the same capabilities both inside and outside of `appium:options`, the values\n inside of `appium:options` take precedence.","metadata":{"headerPath":"## BiDi Protocol Support","sectionCount":2,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## Always-Match and First-Match Capabilities\n\nThe W3C spec allows clients to give the Appium server some flexibility in the kind of session it\ncreates in response to a new session request. This is through the concept of \"always-match\" and\n\"first-match\" capabilities:\n\n- Always-match capabilities consist of a single set of capabilities, every member of which must\n be satisfied by the server in order for the new session request to proceed.\n- First-match capabilities consist of an array of capability sets. Each set is merged with the\n always-match capabilities, and the first set that the server knows how to handle will be the set\n that is used to start the session.\n\n!!! note\n\n Check out the [spec itself](https://w3c.github.io/webdriver/#processing-capabilities) or\n a [summarized version](https://github.com/jlipps/simple-wd-spec#processing-capabilities) for\n a more in-depth description of how capabilities are processed.\n\nIn practice, use of first-match capabilities is not necessary or recommended for use with Appium.\nInstead, we recommend that you define the explicit set of capabilities you want the Appium\nserver to handle. These will be encoded as the always-match capabilities, and the array of\nfirst-match capabilities will be empty.\n\nThat being said, Appium _does_ understand always-match and first-match capabilities as\ndefined in the W3C spec, so if you use these features, Appium will work as expected. The process of\ndefining always-match and first-match capabilities is unique to each client library, so refer to\nthe documentation for your client library to see examples of how it works.\n\n## Special Notes for Cloud Providers\n\n!!! warning\n\n This section is not intended for end-users of Appium; it is intended for developers building\n Appium-compatible cloud services.\n\nWhen managing an Appium cloud, your users may wish to target various independent versions of Appium\ndrivers and plugins. It is of course up to each service provider how they wish to implement the\ndiscovery, installation, and availability of any official or third party drivers or plugins. But\nthe Appium team does provide several suggestions, for consistency across the industry. _These are\nrecommendations only,_ and not a standard, but adopting it will help users to navigate the increased\ncomplexity that working with Appium in a cloud environment may bring.","metadata":{"headerPath":"## Always-Match and First-Match Capabilities","sectionCount":2,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## Special Notes for Cloud Providers > ### Suggested capabilities\n\nIn addition to the standard `platformName`, `appium:deviceName`, `appium:automationName`, and\n`appium:platformVersion`, we recommend adopting the capability `$cloud:appiumOptions`, where the\nlabel `$cloud` is not meant to be interpreted literally but instead should be replaced by your\nvendor prefix (so for HeadSpin it would be `headspin`, Sauce Labs it would be `sauce`, and\nBrowserStack it would be `browserstack`, to name just a few examples). The `$cloud:appiumOptions`\ncapability would itself be a JSON object, with the following internal keys:\n\n| <div style=\"width:10em\">Capability</div> | Usage | Example |\n| ---------------------------------------- | ------ | ------- |\n| `version` | The version of the Appium server that is used to host and manage drivers. If omitted, the behavior is left up to the provider, but the recommendation would be to provide the latest official version. | `2.0.0` |\n| `automationVersion` | The version of the driver (as specified by `appium:automationName`) that should be used. | `1.55.2` |\n| `automation` | The name of a custom driver to use (see below for more info). This would override `appium:automationName` and `$cloud:automationVersion`. | `{\"name\": \"@org/custom-driver\", \"source\": \"github\", \"package\": \"custom-driver\"}` |\n| `plugins` | The list of plugins (and potentially versions of plugins) that should be activated (see below for more info). | `[\"images\", \"universal-xml\"]` |","metadata":{"headerPath":"## Special Notes for Cloud Providers > ### Suggested capabilities","sectionCount":1,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## Special Notes for Cloud Providers > ### Basic example\n\nAppium extensions (drivers and plugins) have a set of properties that specify where they can be\ninstalled from. Cloud providers are obviously under no obligation to provide support for\narbitrarily specified extensions, seeing as these may represent untrusted code running in a managed\nenvironment. In the case where arbitrary extensions are not supported, the `appium:automationName`,\n`$cloud:automationVersion`, and `$cloud:appiumPlugins` capabilities should be sufficient. See the\nfollowing JSON object representing capabilities for a session:\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:platformVersion\": \"14.4\",\n \"appium:deviceName\": \"iPhone 11\",\n \"appium:app\": \"Some-App.app.zip\",\n \"appium:automationName\": \"XCUITest\",\n \"$cloud:appiumOptions\": {\n \"version\": \"2.0.0\",\n \"automationVersion\": \"3.52.0\",\n \"plugins\": [\"images\"]\n }\n}\n```\n\nThis set of capabilities requests an Appium 2+ server supporting the XCUITest driver at version\n`3.52.0`, and the `images` plugin active. This set is easy for a cloud provider to verify. The\ncloud provider can obviously do anything it wants in response to these capabilities, including\ndownloading Appium and driver and plugin packages on the fly, or erroring out if the versions\nrequested are not in a supported set, or if the plugin is not supported, etc...\n\n## Special Notes for Cloud Providers > ### Basic example with `appium:options`\n\nThe previous example still looks a bit disorganized, so of course we also recommend that cloud\nproviders support the `appium:options` capability as detailed above, which could turn the previous\nset of capabilities into the following:\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:options\": {\n \"platformVersion\": \"14.4\",\n \"deviceName\": \"iPhone 11\",\n \"app\": \"Some-App.app.zip\",\n \"automationName\": \"XCUITest\"\n },\n \"$cloud:appiumOptions\": {\n \"version\": \"2.0.0\",\n \"automationVersion\": \"3.52.0\",\n \"plugins\": [\"images\"]\n }\n}\n```","metadata":{"headerPath":"## Special Notes for Cloud Providers > ### Basic example","sectionCount":2,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## Special Notes for Cloud Providers > ### Extension objects\n\nSome service providers may wish to dynamically allow access to all of the features of the Appium\n2 CLI, including downloading arbitrary drivers and plugins. To represent these extensions, we can\ndefine special JSON \"extension objects\", with the following keys:\n\n- `name`: the name of the extension. This would be an `npm` package name (if downloading from `npm`),\n or a `git` or GitHub spec (if downloading from a `git` server or GitHub).\n- `version`: the version of the extension, e.g., the `npm` package version or `git` SHA.\n- (optional) `source`: a denotation of where the extension can be downloaded from. It is recommended\n to support the following values: `appium`, `npm`, `git`, `github`. Here, `appium` means \"Appium's\n own official list\", and should be the default value if this key is not included.\n- (optional) `package`: when downloading extensions from `git` or GitHub, the `npm` package name of\n the extension must also be provided. This is optional for non-`git` sources.\n\nSince each session is handled by a single driver, the `$cloud:appiumOptions`/`$automation`\ncapability could be used with an extension object value to denote this driver, for example:\n\n```json\n{\n \"$cloud:appiumOptions\": {\n \"automation\": {\n \"name\": \"git+https://some-git-host.com/custom-driver-project.git\",\n \"version\": \"some-git-sha\",\n \"source\": \"git\",\n \"package\": \"driver-npm-package-name\"\n }\n }\n}\n```\n\nAnd since sessions can handle multiple plugins, each value in the list of `$cloud:appiumPlugins`\ncould also be an extension object rather than a string, so that specific versions could be\nrequested:\n\n```json\n{\n \"$cloud:appiumOptions\": {\n \"plugins\": [{\n \"name\": \"images\",\n \"version\": \"1.1.0\"\n }, {\n \"name\": \"my-github-org/my-custom-plugin\",\n \"version\": \"a83f2e\",\n \"source\": \"github\",\n \"package\": \"custom-plugin\"\n }]\n }\n}\n```","metadata":{"headerPath":"## Special Notes for Cloud Providers > ### Extension objects","sectionCount":1,"recursiveSplit":true,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"## Special Notes for Cloud Providers > ### Extension objects\n\nThese serve as illustrative examples for the recommendations here. Of course, it is up to the\nservice providers to implement the handling of these capabilities at their front end / load\nbalancer, to perform any error checking, or to actually run any of the `appium driver` or `appium\nplugin` CLI commands that support the end user's request. This section is merely a suggestion as to\nhow service providers might design their user-facing capabilities API in a way which in principle\nsupports all of the capabilities that Appium itself would provide to the end user if they were\nrunning Appium on their own.","metadata":{"headerPath":"## Special Notes for Cloud Providers > ### Extension objects","sectionCount":1,"recursiveSplit":true,"filename":"caps.md","relativePath":"appium/packages/appium/docs/en/guides/caps.md"}},{"pageContent":"---\ntitle: The Appium Config File\n---\n\nInstead of passing arguments on the command line to Appium, you may add them to a special config\nfile. Appium will read values from this config file when it runs. (Please note that CLI arguments\nhave _precedence_ over configuration files; if a value is set in a config file _and_ via CLI\nargument, the CLI argument is preferred.)\n\n## Supported Config File Formats\n\nYou can store your config data in the following kinds of files:\n\n- JSON\n- YAML\n- JS (a JavaScript file exporting a JS object)\n- CJS (the same as above; the extension is for common JS)\n\n!!! warning\n\n Note: Configuration files in ESM format are not currently supported.\n\n## Supported Config File Locations\n\nConfiguration files can be named anything, but the following filenames will be automatically\ndiscovered and loaded by Appium:\n\n- `.appiumrc.json` (recommended)\n- `.appiumrc.yaml`\n- `.appiumrc.yml`\n- `.appiumrc.js`\n- `.appiumrc.cjs`\n- `appium.config.js`\n- `appium.config.cjs`\n- `.appiumrc` (which is considered to be JSON)\n\nFurther, _if your project uses Node.js,_ you can use store the configuration inside an `appium`\nproperty in your `package.json` and it will be automatically discovered.\n\n## Supported Config File Locations > ### Config File Search\n\nAppium will search _up_ the directory tree from the current working directory for one of these\nfiles. If it reaches the current user's home directory or filesystem root, it will stop looking.\n\nTo specify a _custom_ location for your config file, use `appium --config /path/to/config/file`.","metadata":{"headerPath":"","sectionCount":4,"filename":"config.md","relativePath":"appium/packages/appium/docs/en/guides/config.md"}},{"pageContent":"## Supported Config File Locations > ### Config File Search > #### Configuration File Format\n\nFirst, you might want to look at some examples:\n\n- [Appium Configuration - JSON](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.json)\n- [Appium Configuration - YAML](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.yaml)\n- [Appium Configuration - JS](https://github.com/appium/appium/blob/master/packages/appium/sample-code/appium.config.sample.js)\n\nA description of the format is available, as well:\n\n- [Appium Configuration File JSON Schema](https://github.com/appium/appium/blob/master/packages/schema/lib/appium-config.schema.json)\n- [TypeScript declarations for Appium Configuration](https://github.com/appium/appium/blob/master/packages/types/lib/config.ts)\n\nTo describe in words, the config file will have a root `server` property, and all arguments are\nchild properties. For certain properties which must be supplied on the command-line as\ncomma-delimited lists, JSON strings, and/or external filepaths, these instead will be of their\n\"native\" type. For example, `--use-plugins <value>` needs `<value>` to be comma-delimited string\nor path to a delimited file. However, the config file just wants an array, e.g.,:\n\n```json\n{\n \"server\": {\n \"use-plugins\": [\"my-plugin\", \"some-other-plugin\"]\n }\n}\n```\n\n## Configuring extensions (drivers and plugins)\n\nFor `driver`-and-`plugin`-specific configuration, these live under the `server.driver` and\n`server.plugin` properties, respectively. Each driver or plugin will have its own named property,\nand the values of any specific configuration it provides are under this. For example:\n\n```json\n{\n \"server\": {\n \"driver\": {\n \"xcuitest\": {\n \"webkit-debug-proxy-port\": 5400\n }\n }\n }\n}\n```\n\n!!! note\n\n The above configuration corresponds to the `--driver-xcuitest-webkit-debug-proxy-port` CLI argument.\n\nAll properties are case-sensitive and will be in\n[kebab-case](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Delimiter-separated_words).\nFor example, `callback-port` is allowed, but `callbackPort` is not.","metadata":{"headerPath":"## Supported Config File Locations > ### Config File Search > #### Configuration File Format","sectionCount":2,"filename":"config.md","relativePath":"appium/packages/appium/docs/en/guides/config.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Managing Contexts\n---\n\nA common feature of many app platforms is the ability for developers to embed web content inside of\nthe platform-native app frame. This allows developers to leverage web technologies or existing web\ncontent for some or all of the app functionality. However, the additional complexity of mixing\n\"modes\" within a single application can make it difficult for automation tools that are designed to\ntarget the \"native\" elements and behaviours.\n\nAppium provides a set of APIs for working with different app modes, called \"contexts\", that Appium\ndrivers can implement if they support automation commands in these different modes. There are three\nbasic commands that Appium has added to the W3C WebDriver spec for this purpose:\n\n| Command Name | Method/Route | Params | Description | Returns |\n|-----------------------|-----------------------------|-------------------|-----------------------------------------------|-----------------|\n| `Get Contexts` | `GET /session/:id/contexts` | | Get a list of the available contexts | `array<string>` |\n| `Get Current Context` | `GET /session/:id/context` | | Get the name of the active context | `string` |\n| `Set Context` | `POST /session/:id/context` | `name` (`string`) | Switch into the context with the given `name` | `null` |\n\nThis API is flexible enough to handle a variety of semantic interpretations on the part of the\ndriver. For example, the XCUITest driver includes two kinds of contexts: the native app context and\nany active webviews, as one context per webview. A call to `Get Contexts` will return the list of\nnames, which you as a test author can sift through and use to switch into the appropriate context.\nAs another example, the [Appium Altunity\nPlugin](https://github.com/headspinio/appium-altunity-plugin) introduces the concept of a `UNITY`\ncontext, which encapsulates all the plugin's specific behaviour to ensure that when outside of the\n`UNITY` context, the active driver's usual command implementations are used.\n\nIt is important to note that a call to `Get Contexts` will always contain at least one context,\nconventionally but not necessarily named `NATIVE_APP`. This is the default active context.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"context.md","relativePath":"appium/packages/appium/docs/en/guides/context.md"}},{"pageContent":"It is important to note that a call to `Get Contexts` will always contain at least one context,\nconventionally but not necessarily named `NATIVE_APP`. This is the default active context.\n\nDepending on the type of context you're in, the operation of the driver might change. The XCUITest\ndriver, when targeting a webview context, will not run its typical routines for finding and\ninteracting with elements. Instead, it will run a different set of routines appropriate to web\nelements. This might have a variety of consequences, like supporting a different set of locator\nstrategies.\n\nThe command names in the table above are generic references to the commands and not code examples.\nFor examples of how to access the Context API in the language-specific client libraries, please\nvisit the documentation for a given library.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"context.md","relativePath":"appium/packages/appium/docs/en/guides/context.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Retrieving Event Timings\n---\n\nAppium comes with the ability to retrieve timing information about startup\ninformation and command length. This is an advanced feature that is controlled\nby the use of the `appium:eventTimings` capability (set it to `true` to log event\ntimings).\n\nWith this capability turned on, the `POST /session/:id/appium/events` response (i.e., \nthe response to `driver.logs.events` or similar, depending on client) will be \ndecorated with an `events` property. This is the structure of that `events`\nproperty:\n\n```\n{\n \"<event_type>\": [<occurence_timestamp_1>, ...],\n \"commands\": [\n {\n \"cmd\": \"<command_name>\",\n \"startTime\": <js_timestamp>,\n \"endTime\": <js_timestamp>\n },\n ...\n ]\n}\n```\n\nIn other words, the `events` property has 2 kinds of properties of its own:\n\n* Properties which are the names of event types\n* The `commands` property\n\nProperties which are names of event types correspond to an array of timestamps\nwhen that event happened. It's an array because events might happen multiple\ntimes in the course of a session. Examples of event types include:\n\n* `newSessionRequested`\n* `newSessionStarted`\n\n(Individual drivers will define their own event types, so we do not have an\nexhaustive list to share here. It's best to actually get one of these responses\nfrom a real session to inspect the possible event types.)\n\nThe `commands` property is an array of objects. Each object has the name of the\nAppium-internal command (for example `click`), as well as the time the command\nstarted processing and the time it finished processing.\n\nWith this data, you can calculate the time between events, or a strict timeline\nof events, or statistical information about average length of a certain type of\ncommand, and so on.\n\nYou can only receive data about events that have happened when you make the\ncall to `/session/:id/appium/events`, so the best time to get data about an entire session is\nright before quitting it.\n\nThe Appium team maintains an event timings parser tool that can be used to\ngenerate various kinds of reports from event timings output:\n[appium/appium-event-parser](https://github.com/appium/appium-event-parser).\n\n!!! note\n\n In the past, events were available as a part of `GET /session/:id` response","metadata":{"headerPath":"","sectionCount":1,"filename":"event-timing.md","relativePath":"appium/packages/appium/docs/en/guides/event-timing.md"}},{"pageContent":"## Add a custom event\n\nYou can add custom events that will show up in the event timings data. You can send a custom event\nname to the Appium server using the [Log Custom Event API](../reference/api/appium.md#logcustomevent),\nand the server will store the timestamp. The [Get Log Events](../reference/api/appium.md#getlogevents)\ncommand can be used to retrieve named events' timestamps later on.","metadata":{"headerPath":"## Add a custom event","sectionCount":1,"filename":"event-timing.md","relativePath":"appium/packages/appium/docs/en/guides/event-timing.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Execute Methods\n---\n\nBecause the scope of commands implemented in Appium drivers is broader than the scope of commands\ndefined by the W3C WebDriver spec, Appium needs a way for these \"extended\" commands to be accessible\nby client libraries. There are two main strategies for this:\n\n1. Appium drivers define new W3C-compatible API routes, and Appium clients are updated to include\n support for those new routes.\n2. Appium drivers define so-called \"Execute Methods\" which provide new functionality by\n overloading the existing `Execute Script` command which is already available in any WebDriver-\n based client library (including all Selenium and Appium clients).\n\nThere are pros and cons for each strategy, but it is ultimately up to the extension author to\ndecide how they wish implement new commands. \n\nThis guide is designed to specifically help you understand the \"Execute Method\" strategy. This\npattern is commonly used in official Appium drivers and other third-party extensions.\nHere's an example of how the `Execute Script` command is designed to work in the world of WebDriver\nand browser automation:\n\n=== \"JS (WebDriverIO)\"\n\n ```js\n await driver.executeScript('return arguments[0] + arguments[1]', [3, 4])\n ```\n\n=== \"Java\"\n\n ```java\n JavascriptExecutor jsDriver = (JavascriptExecutor) driver;\n jsDriver.executeScript(\"return arguments[0] + arguments[1]\", 3, 4);\n ```\n\n=== \"Python\"\n\n ```py\n driver.execute_script('return arguments[0] + arguments[1]', 3, 4)\n ```\n\n=== \"Ruby\"\n\n ```rb\n driver.execute_script 'return arguments[0] + arguments[1]', 3, 4\n ```\n\n=== \"C#\"\n\n ```dotnet\n ((IJavaScriptExecutor)driver).ExecuteScript(\"return arguments[0] + arguments[1]\", 3, 4);\n ```\n\nWhat's happening here is that we are defining a snippet of Javascript (technically,\na function body) to be executed within the web browser. The client can send arguments which are\nserialized, sent over HTTP, and finally provided to the function as parameters. In this example,\nwe are essentially defining an addition function. The return value of the `Execute Script` command\nis whatever the return value of the Javascript snippet is! In the case of this example, that value\nwould be the number `7` (`3` + `4`).\n\nEach client library has its own way of calling the command and providing any arguments to the script\nfunction, but the function itself—the snippet—is always a string and is the same across all languages.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"execute-methods.md","relativePath":"appium/packages/appium/docs/en/guides/execute-methods.md"}},{"pageContent":"In the world of Appium, we are usually not automating a web browser, which means this command is\nnot particularly useful. But it *is* useful as a way to encode the name of an arbitrary command and\nto provide parameters. For example, the [XCUITest\nDriver](https://github.com/appium/appium-xcuitest-driver) has implemented a command that lets a client\nterminate a running application if you know the ID (the `bundleId`) of the app. The way that the\ndriver makes this command available is via the Execute Method `mobile: terminateApp`. Instead of\nproviding a JavaScript function to the \"Execute Script\" command, the user provides a _known string_\nas defined by the driver. The only other thing a client needs to know is the set of\nparameters for the method, which are documented by the driver. In this case, we have a parameter\nnamed `bundleId`, whose value should be a string encoding the ID of the app to terminate. Here is\nhow this Execute Method would be called:\n\n=== \"JS (WebDriverIO)\"\n\n ```js\n await driver.executeScript('mobile: terminateApp', [{bundleId: 'com.my.app'}])\n ```\n\n=== \"Java\"\n\n ```java\n JavascriptExecutor jsDriver = (JavascriptExecutor) driver;\n jsDriver.executeScript(\"mobile: terminateApp\", ImmutableMap.of(\"bundleId\", \"com.my.app\"));\n ```\n\n=== \"Python\"\n\n ```py\n driver.execute_script('mobile: terminateApp', {'bundleId': 'com.my.app'})\n ```\n\n=== \"Ruby\"\n\n ```rb\n driver.execute_script 'mobile: terminateApp', { bundleId: 'com.my.app' }\n ```\n\n=== \"C#\"\n\n ```dotnet\n ((IJavaScriptExecutor)driver).ExecuteScript(\"mobile: terminateApp\",\n new Dictionary<string, string> { { \"bundleId\", \"com.my.app\" } });\n\n ```\n\nThere are two important differences in using Appium Execute Methods from vanilla Selenium\nJavascript execution:\n\n1. The script string is just a command name; it will be provided by the driver documentation\n1. The standard way to provide parameters is as a *single* object with keys representing parameter\n names and values representing parameter values. So in this case, we had to specify both the\n parameter name (`bundleId`) as the key of the parameters object, and the parameter value\n (`com.my.app`) as the value for that key. A driver can define parameters as _required_ or _optional_.\n\nOf course, always refer to the documentation for the particular Execute Method in case the author\nhas made any alterations to the standard access method.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"execute-methods.md","relativePath":"appium/packages/appium/docs/en/guides/execute-methods.md"}},{"pageContent":"---\ntitle: Appium and Selenium Grid\n---\n\n## Using Selenium Grid 4+\n\nThe\n[relay](https://www.selenium.dev/documentation/grid/configuration/toml_options/#relaying-commands-to-a-service-endpoint-that-supports-webdriver)\nfeature in Grid 4 allows you to proxy Appium requests to an Appium server instance. Here is\nan example walkthrough of how you would connect two different Appium instances to a Selenium Grid.\n\n## Using Selenium Grid 4+ > ### Define the Appium configs\n\nEach Appium instance should have a config file that can be easily updated. It should contain any\ninformation which needs to be unique to that particular server (e.g., ports its drivers should use\nthat others should not). We are going to have 2 Appium servers, so we will need 2 config files:\n\n```yaml\n# appium1.yml\nserver:\n port: 4723\n use-drivers:\n - xcuitest\n default-capabilities:\n wdaLocalPort: 8100\n mjpegServerPort: 9100\n mjpegScreenshotUrl: \"http://localhost:9100\"\n```\n\nIn the above YAML config file, we specify the Appium server port, the driver used, and parameters\nfor the driver that will be sent in as default capabilities. Our goal is to ensure that any other\ndrivers running on this host will not compete with system ports or other resources. The second\nconfig file could look like the following, where we simply adjust a few ports to prevent clashes:\n\n```yaml\n# appium2.yml\nserver:\n port: 4733\n use-drivers:\n - xcuitest\n default-capabilities:\n wdaLocalPort: 8110\n mjpegServerPort: 9110\n mjpegScreenshotUrl: \"http://localhost:9110\"\n```","metadata":{"headerPath":"","sectionCount":3,"filename":"grid.md","relativePath":"appium/packages/appium/docs/en/guides/grid.md"}},{"pageContent":"## Using Selenium Grid 4+ > ### Define the Grid node configs\n\nWe will be launching one Grid \"node\" per Appium server, to manage relaying commands and determining\ncapacity and online status, etc... So we should have one config file per Grid node as well. Each\nnode config should include the address of the Appium server it will target, as well as a list of\ncapability \"configs\" it should accept to relay a session request to Appium. Here is what the config\ncould look like for the two nodes:\n\n```toml\n# node1.toml\n[server]\nport = 5555\n\n[node]\ndetect-drivers = false\n\n[relay]\nurl = \"http://localhost:4723\"\nstatus-endpoint = \"/status\"\nconfigs = [\n \"1\", \"{\\\"platformName\\\": \\\"iOS\\\", \\\"appium:platformVersion\\\": \\\"15.5\\\", \\\"appium:deviceName\\\": \\\"iPhone 13\\\", \\\"appium:automationName\\\": \\\"XCUITest\\\"}\"\n]\n```\n\n```toml\n# node2.toml\n[server]\nport = 5565\n\n[node]\ndetect-drivers = false\n\n[relay]\nurl = \"http://localhost:4733\"\nstatus-endpoint = \"/status\"\nconfigs = [\n \"1\", \"{\\\"platformName\\\": \\\"iOS\\\", \\\"appium:platformVersion\\\": \\\"15.5\\\", \\\"appium:deviceName\\\": \\\"iPhone 12\\\", \\\"appium:automationName\\\": \\\"XCUITest\\\"}\"\n]\n```\n\nNote that each node config also specifies a different port itself for the node to run on.\n\n## Using Selenium Grid 4+ > ### Putting it together\n\nThe Grid nodes aren't enough--you'll also want a Grid \"hub\" that acts as a load balancer and\nmanager for all the nodes. So in the end we'll have 5 processes running at once: 2 Appium servers,\n2 Grid nodes, and 1 Grid hub. It's best to run each of these in a separate terminal window to avoid\nconfusion of logs. Here is how you'd start each process:\n\n0. `appium --config appium1.yml`\n0. `appium --config appium2.yml`\n0. `java -jar /path/to/selenium.jar node --config node1.toml`\n0. `java -jar /path/to/selenium.jar node --config node2.toml`\n0. `java -jar /path/to/selenium.jar hub`\n\nOnce you wait a few moments for the nodes to detect their Appium servers, and to register with the\nhub, you'll be able to send all your Appium traffic via the single hub endpoint (defaulting to\n`http://localhost:4444`).\n\nAnd of course, you're able to link up Appium servers and nodes running on different machines in\nyour network to form a larger grid.","metadata":{"headerPath":"## Using Selenium Grid 4+ > ### Define the Grid node configs","sectionCount":2,"filename":"grid.md","relativePath":"appium/packages/appium/docs/en/guides/grid.md"}},{"pageContent":"## Using Selenium Grid 3\n\nIt is possible to register your Appium server with a local [Selenium Grid 3](https://www.selenium.dev/documentation/legacy/selenium_3/grid_3/)\n([setup docs](https://www.selenium.dev/documentation/legacy/grid_3/setting_up_your_own_grid/)) instance by using the\n`--nodeconfig` server argument.\n\n```bash\nappium server --nodeconfig /path/to/nodeconfig.json --base-path=/wd/hub\n```\n\nIn the referenced config file you have to define the `browserName`, `version` and `platform`\ncapabilities and based on these parameters the grid will re-direct your test to the right device.\nYou will also need to configure your host details and the Selenium Grid details. For a full list of\nall parameters and descriptions see\n[here](https://www.selenium.dev/documentation/legacy/selenium_3/grid_setup/).\n\nOnce you start the Appium server it will register with the grid, and you will see your device on\nthe grid console page:\n\n`http://**\\<grid-ip-adress\\>**:**\\<grid-port\\>**/grid/console`\n\n## Using Selenium Grid 3 > ### Example Grid Node Configuration JSON\n\n```json\n{\n \"capabilities\":\n [\n {\n \"browserName\": \"<e.g._iPhone5_or_iPad4>\",\n \"version\":\"<version_of_iOS_e.g._7.1>\",\n \"maxInstances\": 1,\n \"platform\":\"<platform_e.g._MAC_or_ANDROID>\"\n }\n ],\n \"configuration\":\n {\n \"cleanUpCycle\":2000,\n \"timeout\":30000,\n \"proxy\": \"org.openqa.grid.selenium.proxy.DefaultRemoteProxy\",\n \"url\":\"http://<host_name_appium_server_or_ip-address_appium_server>:<appium_port>/wd/hub\",\n \"host\": \"<host_name_appium_server_or_ip-address_appium_server>\",\n \"port\": <appium_port>,\n \"maxSession\": 1,\n \"register\": true,\n \"registerCycle\": 5000,\n \"hubPort\": <grid_port>,\n \"hubHost\": \"<Grid_host_name_or_grid_ip-address>\",\n \"hubProtocol\": \"<Protocol_of_Grid_defaults_to_http>\"\n }\n}\n```\n\nIf `url`, `host`, and `port` are not given, the config will be auto updated to point to\n`localhost:<appium-port>`.\n\nIf your Appium server is running on a different machine to your Selenium Grid server, make sure you\nuse an external name/IP address in your `host` and `url` configuration; `localhost` and `127.0.0.1`\nwill prevent Selenium Grid from connecting correctly.","metadata":{"headerPath":"## Using Selenium Grid 3","sectionCount":2,"filename":"grid.md","relativePath":"appium/packages/appium/docs/en/guides/grid.md"}},{"pageContent":"---\ntitle: Header Handling\n---\n\n# Header Handling\n\n# Header Handling > ## Request ID Tracking\n\nAppium supports setting the request ID for each request through the `x-request-id` header. This is useful for tracing requests through your system, especially in environments where multiple services are involved or when debugging across different requests.\n\n# Header Handling > ## Request ID Tracking > ### Using `x-request-id`\n\nWhen making requests to Appium, you can include an `x-request-id` header with a unique identifier. This ID will be:\n\n- Used to track the request through Appium's logging system\n- Preserved across the entire request lifecycle\n- Generated automatically (as a UUID) if not provided","metadata":{"headerPath":"","sectionCount":4,"filename":"headers.md","relativePath":"appium/packages/appium/docs/en/guides/headers.md"}},{"pageContent":"---\ntitle: Filtering the Appium Log\n---\n\nSometimes it might be necessary to hide sensitive information, like passwords, device identifiers,\nhashes, etc..., from the server log. Appium makes it possible to ensure such information is\nredacted in logs via the `--log-filters` command line argument. This argument allows you to provide\nthe path to a special config file, containing one or more log obfuscation rules.\n\n## Config Format\n\nThe filtering config must be one of:\n\n- a path to a valid JSON file containing an array of filtering rules\n- a `log-filters` entry in an [Appium Config](./config.md) file, with the rules array inline\n\nEach rule is an object with a set of predefined properties. The following rule properties are\nsupported:\n\n- `pattern`: A valid Javascript RegExp pattern to replace. Must be a valid non-empty pattern.\n- `text`: A simple non-empty exact text match to replace. Either this property or the above one must\n be provided. `pattern` has priority over `text` if both are provided.\n- `flags`: Regular expression flags for the given pattern. Supported flags are the same as for the\n standard JavaScript [RegExp constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2).\n Note that the `g` (global matching) flag is always enabled.\n- `replacer`: The replacer value to use. By default it is `**SECURE**`. Empty values are allowed.\n\n## Config Format > ### Config Examples\n\nReplace all occurrences of `my.magic.app` string with the default replacer:\n\n```json\n[\n {\n \"text\": \"my.magic.app\"\n }\n]\n```\n\nReplace all occurrences of `my.magic.<any char>` string with a custom replacer (case insensitive):\n\n```json\n[\n {\n \"pattern\": \"my\\\\.magic\\\\.\\\\w\",\n \"flags\": \"i\",\n \"replacer\": \"***\"\n }\n]\n```\n\nReplace all occurrences of `my.magic.<any chars>` and/or `your.magic` strings with a custom\nreplacer (case insensitive):\n\n```json\n[\n {\n \"pattern\": \"my\\\\.magic\\\\.\\\\w+\",\n \"flags\": \"i\",\n \"replacer\": \"***\"\n },\n {\n \"pattern\": \"your\\\\.magic\",\n \"flags\": \"i\",\n \"replacer\": \"***\"\n }\n]\n```\n\nTruncate all log lines to max 15 chars (advanced):\n\n```json\n[\n\t{\n \"pattern\": \"(.{1,15}).*\",\n \"flags\": \"s\",\n \"replacer\": \"$1\"\n }\n]\n```","metadata":{"headerPath":"","sectionCount":3,"filename":"log-filters.md","relativePath":"appium/packages/appium/docs/en/guides/log-filters.md"}},{"pageContent":"## Config Format > ### Config Errors Handling\n\nIf any of the config rules contains invalid items (such as empty/invalid pattern, empty rule, etc.)\nthen Appium will print the detailed report about collected errors and will fail to start until\nthese errors are addressed.","metadata":{"headerPath":"## Config Format > ### Config Errors Handling","sectionCount":1,"filename":"log-filters.md","relativePath":"appium/packages/appium/docs/en/guides/log-filters.md"}},{"pageContent":"---\ntitle: Managing Drivers and Plugins\n---\n\nTo do anything useful with Appium, you need to have at least one [Driver](../intro/drivers.md)\ninstalled, otherwise Appium won't know how to automate anything. There is an entire\n[Ecosystem](../ecosystem/index.md) of drivers and plugins out there!\n\nThis guide helps explain how to manage these drivers and plugins. There are\ntwo basic strategies: using Appium's extension CLI interface, or managing extensions yourself in an\n`npm`-based project.\n\n!!! note\n\n Other package managers are not currently supported.\n\n## Using Appium's Extension CLI\n\nWith Appium's [Extension CLI](../reference/cli/extensions.md), you let Appium manage drivers and plugins for\nyou. You will use CLI commands to tell Appium which extensions you would like to install, update,\nor remove. Here's an example of how you might install a driver using the CLI:\n\n```bash\nappium driver install xcuitest\n```\n\nThis command will install the latest version of the\n[XCUITest Driver](https://github.com/appium/appium-xcuitest-driver). The Extension CLI comes with a variety\nof commands and parameters; see the documentation for that command for all the specifics.\n\nThe all-important question when Appium is managing your extensions for you is: where are they installed?\nAppium manages extensions in a directory specified by the `APPIUM_HOME` environment variable. You\ncan set that variable to anything you like, and Appium will manage its extensions there. You can\ntherefore also use the `APPIUM_HOME` environment variable to manage different sets of extensions,\nfor example if you want to have the same driver installed at conflicting versions:\n\n```bash\nAPPIUM_HOME=/path/to/home1 appium driver install xcuitest@4.11.1\nAPPIUM_HOME=/path/to/home2 appium driver install xcuitest@4.11.2\n```\n\nRunning these commands will result in two separate `APPIUM_HOME` directories being created and\npopulated with the corresponding version of the XCUITest driver. You can then use the same\nenvironment variables to direct Appium which version to use on launch:\n\n```bash\nAPPIUM_HOME=/path/to/home1 appium # use xcuitest driver 4.11.1\nAPPIUM_HOME=/path/to/home2 appium # use xcuitest driver 4.11.2\n```\n\nYou don't need to set `APPIUM_HOME` if you don't want to! By default, Appium will set `APPIUM_HOME`\nto the directory `.appium` in your user home directory.\n\nThese installed packages will be managed by `extensions.yaml` in `$APPIUM_HOME/node_modules/.cache/appium/extensions.yaml`.","metadata":{"headerPath":"","sectionCount":2,"filename":"managing-exts.md","relativePath":"appium/packages/appium/docs/en/guides/managing-exts.md"}},{"pageContent":"## Do-It-Yourself with `npm`\n\nBecause Appium and Appium drivers are Node.js programs, if you are integrating your Appium scripts\ninto your own Node.js project, there is an alternative way to manage drivers and plugins: via `npm`,\nlike any other dependency. Basically, whenever you run Appium, if you have not explicitly set\n`APPIUM_HOME`, it will:\n\n1. Try to determine whether the _current directory_ is inside an `npm` package.\n1. If so, it will check whether `appium` is a dependency (dev, prod, or peer) in the project's\n `package.json`\n1. If so, _unless you have specified `APPIUM_HOME` in your environment_, Appium will ignore load\n drivers and plugins defined in that `package.json` file instead.\n\nThis means you are freely able to add Appium drivers and plugins as regular package dependencies or\ndev dependencies. For example, if your project has a `package.json` which includes the following:\n\n```json\n{\n \"devDependencies\": {\n \"appium\": \"^2.0.0\",\n \"appium-xcuitest-driver\": \"^4.11.1\"\n }\n}\n```\n\nThen, if you run `npx appium` inside your project, Appium will detect that it is a dependency of\nthe project, and will load the XCUITest driver which is also listed as a dev dependency for the\nproject.\n\nThis strategy is *only* recommended if you are already using `npm` for your project.\nOtherwise, it is recommended that you use Appium's Extension CLI and, if necessary, adjust\n`APPIUM_HOME` to change the location of stored extensions.","metadata":{"headerPath":"## Do-It-Yourself with `npm`","sectionCount":1,"filename":"managing-exts.md","relativePath":"appium/packages/appium/docs/en/guides/managing-exts.md"}},{"pageContent":"---\ntitle: Migrating to Appium 2\n---\n\nThis document is a guide for those who are using Appium 1 and wish to migrate to Appium 2. It\ncontains a list of breaking changes and how to migrate your environments or test suites to ensure\ncompatibility with Appium 2.\n\nAppium 2 is the biggest Appium release in over 5 years. It is _not_ focused on changing the\nautomation behavior for any particular platform, but instead re-envisions Appium into an\n_ecosystem_ of automation tools:\n\n* The core Appium module retains only platform-agnostic functionality\n* Functionality for automating specific platforms is moved to separate _driver_ modules\n* Functionality for altering/extending Appium is moved to separate _plugin_ modules\n\nAt the same time, the Appium project is taking the opportunity to remove many old and deprecated\nbits of functionality.\n\nSince Appium 2 is a major architectural change, ^^we do not recommend directly updating your\nAppium 1 installations to Appium 2^^. Instead, please uninstall Appium 1 first, and only install\nAppium 2 afterwards.\n\n## Breaking Changes\n\n## Breaking Changes > ### Drivers Installed Separately\n\nWhen installing Appium 1, all available drivers would be installed alongside the main Appium\nserver. In Appium 2, due to its modular structure, this is no longer the case - by default,\ninstalling it only installs the core Appium server, without any drivers.\n\nWhen it comes to installing Appium 2 drivers, there are several approaches you can take:\n\n* Add the `--drivers` flag when installing Appium, for example:\n```bash\nnpm i -g appium --drivers=xcuitest,uiautomator2\n```\n* Use the [Appium Extension CLI](../reference/cli/extensions.md), for example:\n```bash\nappium driver install uiautomator2\n```\n* Use the [Appium Setup CLI command](../reference/cli/setup.md) (added in Appium `2.6`), for example:\n```bash\nappium setup mobile\n```\n\nCheck the [Managing Drivers and Plugins guide](./managing-exts.md) for more information.\n\n!!! info \"Actions Needed\"\n\n When installing Appium 2, use one of the above approaches for installing your desired drivers","metadata":{"headerPath":"","sectionCount":3,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"## Breaking Changes > ### Driver Installation Path Changed\n\nWhen installing Appium 1, all available drivers would be installed as dependencies of the main\nAppium server, in `/path/to/appium/node_modules`. For example, `appium-webdriveragent` was located\nat `/path/to/appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`.\n\nIn Appium 2, drivers (and plugins) are installed at the path defined by the `APPIUM_HOME`\nenvironment variable, whose default value is `~/.appium`. So, `appium-webdriveragent` would now be\nlocated at `$APPIUM_HOME/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent`.\n\n!!! info \"Actions Needed\"\n\n If your code uses paths to Appium driver files, update it to use the `APPIUM_HOME` environment\n variable\n\n## Breaking Changes > ### Drivers Updated Separately\n\nIn Appium 1, in order to get updates to your drivers, you would simply wait for those updates to be\nrolled into a new release of Appium, and then update your Appium version. With Appium 2, since the\nserver and drivers are separate packages, they can release new versions independently from each\nother - this means that you no longer need to wait for a new Appium server release, but can install\nthe latest driver versions right away.\n\nChecking for driver updates is done by using the [Appium Extension CLI](../reference/cli/extensions.md):\n\n```bash\nappium driver list --updates\n```\n\nIf any updates are available, you can then run the `update` command for any given driver:\n\n```bash\nappium driver update xcuitest\n```\n\nUpdating the Appium server itself is the same as before:\n\n```bash\nnpm update -g appium\n```\n\nHowever, in Appium 2 this process is a lot quicker, since drivers are no longer bundled with the\nserver package.\n\n!!! info \"Actions Needed\"\n\n Make sure to use the [Appium Extension CLI](../reference/cli/extensions.md) to manage your drivers","metadata":{"headerPath":"## Breaking Changes > ### Driver Installation Path Changed","sectionCount":2,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"## Breaking Changes > ### Deprecated Packages No Longer Supported\n\nThe Appium 1 ecosystem included several drivers, clients and other packages that had since been\ndeprecated and replaced with newer packages. Appium 2 no longer includes support for these packages,\nand it is recommended to migrate to the following replacements:\n\n|Appium 1 Package|Replacement in Appium 2|\n|--|--|\n|iOS Driver|[XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/latest/)|\n|UiAutomator Driver|[UiAutomator2](https://github.com/appium/appium-uiautomator2-driver/)|\n|`wd` Client|[WebdriverIO Client](https://webdriver.io/)|\n|Appium Desktop|[Appium Inspector](https://github.com/appium/appium-inspector)|\n\n!!! info \"Actions Needed\"\n\n If you are using any of the aforementioned package(s), migrate to their recommended replacement(s)\n\n## Breaking Changes > ### Default Server Base Path Changed\n\nIn Appium 1, the default Appium server URL was `http://localhost:4723/wd/hub`, where the `/wd/hub`\npart (the base path) was a legacy convention from Selenium 1. Appium 2 changes the default base\npath to `/`, therefore the default server URL is now `http://localhost:4723/`.\n\n!!! info \"Actions Needed\"\n\n In your test scripts, change the base path of the target server URL from `/wd/hub` to `/`.\n Alternatively, you can retain the Appium 1 base path by launching Appium with the\n `--base-path=/wd/hub` [command-line argument](../reference/cli/server.md).\n\n## Breaking Changes > ### Server Port 0 No Longer Supported\n\nIn Appium 1, it was possible to specify `--port 0` during server startup, which had the effect of\nstarting Appium on a random free port. Appium 2 no longer allows this, and requires port values to\nbe `1` or higher. If you wish to start Appium on a random port, you must now take care of this on\nyour own prior to launching the server.\n\n!!! info \"Actions Needed\"\n\n If you are launching Appium with `--port 0`, change the port number value to `1` or higher","metadata":{"headerPath":"## Breaking Changes > ### Deprecated Packages No Longer Supported","sectionCount":3,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"## Breaking Changes > ### Driver-Specific CLI Options Changed\n\nWith Appium 1, command-line options specific to particular drivers were all hosted on the main\nAppium server. So, for example, `--chromedriver-executable` was a CLI parameter you could use to\nset the Chromedriver location for the UiAutomator2 driver.\n\nIn Appium 2, all driver-specific CLI options have been moved to the drivers themselves. However,\ndepending on the driver, these options may now need to be passed in another way:\n\n* Some options can still be passed as different CLI flags, for example:\n```bash\nappium --webdriveragent-port=5000 # Appium 1\nappium --driver-xcuitest-webdriveragent-port=5000 # Appium 2\n```\n* Some options can now be passed as environment variables, for example:\n```bash\nappium --chromedriver-version=100 # Appium 1\nCHROMEDRIVER_VERSION=100 appium # Appium 2\n```\n* Some options can now be passed as [capabilities](./caps.md), for example:\n```\nappium --chromedriver-executable=/path/to/chromedriver # Appium 1\n{\"appium:chromedriverExecutable\": \"/path/to/chromedriver\"} # Appium 2\n```\n\n!!! info \"Actions Needed\"\n\n If you are using driver-specific CLI options, refer to that driver's documentation for how to\n apply them in Appium 2\n\n## Breaking Changes > ### Filepaths No Longer Supported for Some CLI Options\n\nIn Appium 1, some server command-line options could be invoked by passing a filepath as their\nvalue, and Appium would then parse the contents of that file as the actual value for that option.\nThere were four options that supported this:\n\n* `--nodeconfig`\n* `--default-capabilities`\n* `--allow-insecure`\n* `--deny-insecure`\n\nAppium 2 no longer attempts to parse the contents of filepaths passed to these options, and offers\ntwo ways to specify the value for these options:\n\n* As strings, directly on the command line\n * `--nodeconfig` / `--default-capabilities`: JSON string\n * `--allow-insecure` / `--deny-insecure`: comma-separated list\n* In the [Appium Configuration file](./config.md)\n\n!!! info \"Actions Needed\"\n\n If you are using any of the aforementioned CLI options with a filepath value, update your code\n to pass the file contents either directly or through the Appium config file","metadata":{"headerPath":"## Breaking Changes > ### Driver-Specific CLI Options Changed","sectionCount":2,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"## Breaking Changes > ### Old Protocols Dropped\n\nAppium's API is based on the [W3C WebDriver Protocol](https://www.w3.org/TR/webdriver/), and it has\nsupported this protocol for years. Before this protocol was designed as a web standard, the \n[JSON Wire Protocol](https://www.selenium.dev/documentation/legacy/json_wire_protocol/) (JSONWP)\nand [Mobile JSON Wire Protocol](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)\n(MJSONWP) were used instead.\n\nIn Appium 1, all of these protocols were supported, so that older Selenium/Appium clients could\nstill communicate with newer Appium servers. Appium 2 removes support for JSONWP/MJSONWP and is now\nonly compatible with the W3C WebDriver Protocol.\n\n!!! info \"Actions Needed\"\n\n Make sure you are using Selenium/Appium clients compatible with the W3C WebDriver Protocol","metadata":{"headerPath":"## Breaking Changes > ### Old Protocols Dropped","sectionCount":1,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"## Breaking Changes > ### Capabilities Require Vendor Prefix\n\nIn Appium 1, in order to create a session, you had to specify certain desired capabilities, which\nwould indicate session parameters, e.g. the driver you want to use. Appium 2 retains this behavior\nand continues to accept desired capabilities (now renamed simply to 'capabilities'), but as part of\nthe W3C WebDriver Protocol specification, all non-standard capabilities are now required to use a\nvendor prefix. \n\nThe list of standard capabilities is described in the [WebDriver Protocol specification](https://www.w3.org/TR/webdriver/#capabilities),\nand includes a few commonly used capabilities like `browserName` and `platformName`. All other\ncapabilities must now start with the vendor name and a colon (the vendor prefix), for example,\n`moz:` or `goog:`. Since most of Appium's capabilities go beyond the standard W3C capabilities,\nall of them must include the `appium:` prefix (unless specified otherwise):\n\n```\ndeviceName # Appium 1\nappium:deviceName # Appium 2\n```\n\nThis requirement may or may not be a breaking change for your test suites. Up-to-date versions of\nofficial Appium clients and the Appium Inspector will automatically add the `appium:` prefix to all\nnon-standard capabilities, and the same may apply to cloud-based Appium providers.\n\nAdditionally, if you are starting a session with multiple Appium-specific capabilities (which will\nlikely be the case), it may seem repetitive to add the `appium:` prefix to each individual\ncapability. To avoid this, you can optionally group up all these capabilities under a single object\ncapability, `appium:options`, for example:\n\n=== \"Default Approach\"\n\n ```json\n {\n \"platformName\": \"iOS\",\n \"browserName\": \"Safari\",\n \"appium:platformVersion\": \"14.4\",\n \"appium:deviceName\": \"iPhone 11\",\n \"appium:automationName\": \"XCUITest\"\n }\n ```\n\n=== \"With `appium:options`\"\n\n ```json\n {\n \"platformName\": \"iOS\",\n \"browserName\": \"Safari\",\n \"appium:options\": {\n \"platformVersion\": \"14.4\",\n \"deviceName\": \"iPhone 11\",\n \"automationName\": \"XCUITest\"\n }\n }\n ```\n\n!!! warning\n\n Capabilities included in the `appium:options` object will overwrite capabilities of the same\n name that are used outside of this object. Note that cloud provider support for the\n `appium:options` syntax may vary.\n\nFor more information on capabilities, have a look at the [Capabilities Guide](./caps.md).\n\n!!! info \"Actions Needed\"","metadata":{"headerPath":"## Breaking Changes > ### Capabilities Require Vendor Prefix","sectionCount":1,"recursiveSplit":true,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"## Breaking Changes > ### Capabilities Require Vendor Prefix\n\nFor more information on capabilities, have a look at the [Capabilities Guide](./caps.md).\n\n!!! info \"Actions Needed\"\n\n Add the `appium:` prefix to all Appium-specific capabilities used in your tests, or wrap them\n inside an `appium:options` object","metadata":{"headerPath":"## Breaking Changes > ### Capabilities Require Vendor Prefix","sectionCount":1,"recursiveSplit":true,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"## Breaking Changes > ### Advanced Features Moved to Plugins\n\nOne of the design goals for Appium 2 is to extract non-core features into special extensions called\n[plugins](../ecosystem/plugins.md). Two such features of Appium 1 have been moved to plugins, and\nare no longer bundled with Appium 2:\n\n|Feature|Plugin Name|\n|--|--|\n|Image-related features (comparison, search by image, etc...)|[`images`](https://github.com/appium/appium/tree/master/packages/images-plugin)|\n|The Execute Driver Script feature|[`execute-driver`](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin)|\n\n!!! info \"Actions Needed\"\n\n If you were using the image-related features and/or the execute driver script feature in Appium\n 1, first install their plugin(s):\n ```\n appium plugin install images \n appium plugin install execute-driver\n ```\n Afterwards, make sure to activate the plugin(s) upon launching the Appium server:\n ```\n appium --use-plugins=images,execute-driver\n ```\n\n## Breaking Changes > ### Endpoint Changes\n\nA few server endpoints used in Appium 1 were accepting old or unused parameters. Appium 2 removes\nsupport for these parameters. The following is a list of these changed endpoints, along with the\nparameters they no longer accept, as well as the parameters they continue to accept in Appium 2.\n\n* `POST /session/:sessionId/appium/device/gsm_signal`\n * :octicons-x-24: `signalStrengh`\n * :octicons-check-24: `signalStrength`\n* `POST /session/:sessionId/appium/element/:elementId/value`\n * :octicons-x-24: `value`\n * :octicons-check-24: `text`\n* `POST /session/:sessionId/appium/element/:elementId/replace_value`\n * :octicons-x-24: `value`\n * :octicons-check-24: `text`\n\n!!! info \"Actions Needed\"\n\n Check your Appium client documentation for the methods using these endpoints, and adjust your\n code to only use the accepted parameters\n\n## Breaking Changes > ### Internal Packages Renamed\n\nIn Appium 1, the internal dependency packages were each located in their own repository. Appium 2\nmoves to a monorepo structure and therefore renames many of these packages, for example:\n\n```\nappium-base-driver # Appium 1\n@appium/base-driver # Appium 2\n```\n\n!!! info \"Actions Needed\"\n\n If you do not directly import Appium packages into your code - none! However, if you do, make\n sure to update the names of your Appium package imports!","metadata":{"headerPath":"## Breaking Changes > ### Advanced Features Moved to Plugins","sectionCount":3,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"## Major New Features\n\nApart from the breaking changes mentioned above, here are some of the major new features you may\nwish to take advantage of with Appium 2:\n\n## Major New Features > ### Third-Party Drivers and Plugins\n\nYou are no longer limited to official drivers or plugins, or ones that the Appium team even knows\nabout! Developers can now create their own custom drivers or plugins, which can be installed via\nAppium's [Extension CLI](../reference/cli/extensions.md) from `npm`, `git`, GitHub, or even the local\nfilesystem. Interested in building a driver or plugin? Check out the\n[Building Drivers](../developing/build-drivers.md) and\n[Building Plugins](../developing/build-plugins.md) guides.\n\n## Major New Features > ### Configuration Files\n\nAppium now supports _configuration files_ in addition to command-line arguments. Nearly all options\nor flags that had to be specified on the CLI in Appium 1, can now also be provided in a\nconfiguration file. The file can be in JSON, JS, or YAML format. For more information, refer to\nthe [Config File Guide](./config.md).\n\n## Special Notes for Cloud Providers\n\nMost of this guide has applied to Appium end users or developers, but some of the architectural\nchanges in Appium 2 will constitute breaking changes for different Appium service providers. At the\nend of the day, the maintainer of the Appium server is responsible for installing and exposing the\nvarious Appium drivers and plugins that end users may wish to use.\n\nWe encourage cloud providers to thoroughly read and understand our [recommendation for cloud\nprovider capabilities](./caps.md#special-notes-for-cloud-providers) in order to support user needs in\nan industry-compatible way!","metadata":{"headerPath":"## Major New Features","sectionCount":4,"filename":"migrating-1-to-2.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-1-to-2.md"}},{"pageContent":"---\ntitle: Migrating to Appium 3\n---\n<style>\n .md-typeset .grid {\n grid-template-columns: repeat(auto-fit,minmax(min(100%,11rem),1fr));\n }\n</style>\n\nThis document is a guide for those who are using Appium 2 and would like to upgrade to Appium 3.\nIt contains a list of breaking changes, as well as suggestions for handling them.\n\nWhile Appium 2 was a major overhaul of the entire Appium architecture, Appium 3 is a smaller\nupgrade with fewer breaking changes, which should result in a much simpler migration process.\n\n## Installation\n\nThe installation method for Appium 3 remains the same as for Appium 2. If you want to upgrade, you\ncan simply install Appium 3 on top of your existing installation:\n\n```bash\n# optional: `appium setup reset`\nnpm install -g appium\n```\n\n## Breaking Changes\n\n## Breaking Changes > ### Node 20+ Required\n\nWith Appium 2, the minimum required Node version was `14.17.0`. Support for Node 14 had already\nended before the release of Appium 2, which meant that even users on outdated Node versions were\nable to use it.\n\nAppium 3 drops support for outdated Node versions, and bumps the minimum required version to Node\n`20.19.0` (with the semver range `^20.19.0 || ^22.12.0 || >=24.0.0`), as well as the minimum `npm`\nversion to `10`.\n\n!!! info \"Actions Needed\"\n\n Upgrade Node.js to `v20.19.0` or newer, and `npm` to `v10` or newer\n\n## Breaking Changes > ### Deprecated Endpoints Removed\n\nAppium 3 removes many previously deprecated server endpoints. Some of these endpoints have now\nbecome specific to one or more drivers, while most others have direct or close-to-direct\nreplacements in other endpoints. All removed endpoints, along with replacements (where applicable)\nare listed [in the **Removed Endpoints** section](#removed).\n\nSome W3C endpoints used in Appium also existed in the old JSONWP standard, but required different\nparameters. With Appium 2, both standards for these endpoints were supported. Appium 3 changes\nthese endpoints by removing support for the JSONWP parameters, and only accepting the W3C\nparameters. These endpoints are listed [in the **Modified Endpoints** section](#modified).\n\n!!! info \"Actions Needed\"\n\n Check your Appium client documentation for the affected methods, and adjust your code to use\n their replacements","metadata":{"headerPath":"","sectionCount":5,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Breaking Changes > ### Feature Flag Prefix Required\n\nWith Appium 2, it was possible to opt into certain [insecure features](./security.md) on server\nstartup, which could be enabled using the `--allow-insecure` or `--relaxed-security` flags. Appium\n`2.13` added the ability to optionally provide a scope prefix to specific features, ensuring that\nthey would only be enabled for the specified driver (or all of them).\n\nAppium 3 makes the scope prefix mandatory, and will throw an error if features are specified\nwithout a scope. Note that the behavior of the `--relaxed-security` flag remains unchanged.\n\n!!! info \"Actions Needed\"\n\n If you use the `--allow-insecure` server flag, add a scope prefix before each feature name.\n For example, if you use the UiAutomator2 `adb_shell` feature, on Appium 2 you would enable it\n like this:\n ```\n appium --allow-insecure=adb_shell\n ```\n On Appium 3, to ensure this feature is only activated for UiAutomator2, you can run it like so:\n ```\n appium --allow-insecure=uiautomator2:adb_shell\n ```\n Alternatively, if you wish to keep the Appium 2 behavior and enable the feature for _all_\n drivers that support it, you can use the wildcard (`*`) prefix:\n ```\n appium --allow-insecure=*:adb_shell\n ```\n Server-scope features like `session_discovery` also require the wildcard prefix.","metadata":{"headerPath":"## Breaking Changes > ### Feature Flag Prefix Required","sectionCount":1,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Breaking Changes > ### Session Discovery Requires Feature Flag\n\nIn Appium 2, it was possible to retrieve all active server sessions via the `GET /sessions`\nendpoint. This information could then be used, for example, in Appium Inspector, in order to attach\nto an existing session, instead of creating a new one.\n\nAppium 3 makes two changes to the session discovery process:\n\n* The `GET /sessions` endpoint is replaced with `GET /appium/sessions` (see [the Removed Endpoints section](#removed))\n* The use of the new endpoint requires the `session_discovery` [feature flag](./security.md)\n\nThe return value of `GET /appium/sessions` is largely identical to `GET /sessions`, but additionally\nincludes the `created` field for each session entry, indicating the session creation time as a Unix\ntimestamp. The rest of the result format remains unchanged.\n\nTo reduce migration efforts, the `GET /appium/sessions` endpoint (locked behind the aforementioned\nfeature flag) is also available in Appium `2.19`, allowing you to adjust your code before upgrading\nto Appium 3. As for Appium Inspector, support for this new endpoint is available starting from\nversion `2025.3.1`.\n\n!!! info \"Actions Needed\"\n\n * If your code uses session retrieval, change the endpoint from `GET /sessions` to\n `GET /appium/sessions`\n * If you use Appium Inspector's Attach to Session feature, upgrade to version `2025.3.1` or later\n * In both cases, ensure your Appium server is launched with the `session_discovery`\n [feature flag](./security.md)\n\n## Breaking Changes > ### Unzip Logic Removed\n\nAppium 3 removes the custom unzip logic used when working with files like application packages.\nSuch files are often only relevant to particular platforms, therefore the functionality for\nhandling these operations has been moved to relevant drivers.\n\n!!! info \"Actions Needed\"\n\n Ensure you are using the most recent versions of your drivers\n\n## Breaking Changes > ### Express 5\n\nAppium 3 upgrades the internally-used `express` dependency from `v4` to `v5`. This should not\naffect users who use Appium directly, but developers integrating parts of Appium into their own\nprojects may want to check [the Express 5 Migration Guide](https://expressjs.com/en/guide/migrating-5.html).\n\n!!! info \"Actions Needed\"\n\n None! (hopefully)\n\n## Endpoint Changes","metadata":{"headerPath":"## Breaking Changes > ### Session Discovery Requires Feature Flag","sectionCount":4,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\nThe following is a list of all the Appium server endpoints removed in Appium 3. For ease of\nmigration, additional information is provided for each endpoint: drivers that still support the\nendpoint; suggested replacement endpoints, or, rarely, the lack of any available replacements.\n\nIcons are used to indicate endpoint support in either certain drivers, or in the core Appium server\n(applicable to all drivers):\n\n<div class=\"grid cards\" markdown>\n\n- :simple-appium:{ .lg } - Appium server\n- :material-apple:{ .lg } - [XCUITest driver](https://appium.github.io/appium-xcuitest-driver/latest/)\n- :material-android:{ .lg } - [UiAutomator2 driver](https://github.com/appium/appium-uiautomator2-driver/)\n- :material-coffee:{ .lg } - [Espresso driver](https://github.com/appium/appium-espresso-driver)\n- :material-apple-finder:{ .lg } - [Mac2 driver](https://github.com/appium/appium-mac2-driver)\n- :material-microsoft-windows:{ .lg } - [Windows driver](https://github.com/appium/appium-windows-driver)\n\n</div>","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* `GET /sessions`\n * :octicons-arrow-right-24: `GET /appium/sessions` :simple-appium:\n* `POST /session/:sessionId/accept_alert`\n * :octicons-arrow-right-24: `POST /session/:sessionId/alert/accept` :simple-appium:\n * :octicons-arrow-right-24: `mobile: alert` [execute method](./execute-methods.md) :material-apple:\n * :octicons-arrow-right-24: `mobile: acceptAlert` execute method :material-android:\n* `GET /session/:sessionId/alert_text`\n * :octicons-arrow-right-24: `GET /session/:sessionId/alert/text` :simple-appium:\n* `POST /session/:sessionId/alert_text`\n * :octicons-arrow-right-24: `POST /session/:sessionId/alert/text` :simple-appium:\n* `POST /session/:sessionId/appium/app/background`\n * :octicons-arrow-right-24: `mobile: backgroundApp` execute method :material-apple: :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/app/close`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `mobile: terminateApp` execute method :material-apple: :material-android: :material-coffee:\n * :octicons-arrow-right-24: `macos: terminateApp` execute method :material-apple-finder:\n * :octicons-arrow-right-24: `windows: closeApp` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/appium/app/end_test_coverage`\n * :octicons-arrow-right-24: `mobile: shell` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/app/launch`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `mobile: launchApp` execute method :material-apple:\n * :octicons-arrow-right-24: `mobile: activateApp` or `mobile: startActivity` execute methods :material-android: :material-coffee:\n * :octicons-arrow-right-24: `macos: launchApp` or `macos: activateApp` execute methods :material-apple-finder:\n * :octicons-arrow-right-24: `windows: launchApp` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/appium/app/reset`\n * :octicons-arrow-right-24: `mobile: clearApp` execute method :material-apple: [^sim] :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/app/strings`\n * :octicons-arrow-right-24: `mobile: getAppStrings` execute method :material-apple: :material-android: :material-coffee:\n* `GET /session/:sessionId/appium/device/app_state`\n * :octicons-arrow-right-24: `POST /session/:sessionId/appium/device/app_state` :simple-appium:","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* `GET /session/:sessionId/appium/device/app_state`\n * :octicons-arrow-right-24: `POST /session/:sessionId/appium/device/app_state` :simple-appium:\n * :octicons-arrow-right-24: `mobile: queryAppState` execute method :material-apple: :material-android: :material-coffee:\n * :octicons-arrow-right-24: `macos: queryAppState` execute method :material-apple-finder:\n* `GET /session/:sessionId/appium/device/current_activity`\n * :octicons-arrow-right-24: `mobile: getCurrentActivity` execute method :material-android: :material-coffee:\n* `GET /session/:sessionId/appium/device/current_package`\n * :octicons-arrow-right-24: `mobile: getCurrentPackage` execute method :material-android: :material-coffee:\n* `GET /session/:sessionId/appium/device/display_density`\n * :octicons-arrow-right-24: `mobile: getDisplayDensity` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/finger_print`\n * :octicons-arrow-right-24: `mobile: fingerPrint` execute method :material-android: [^sim] :material-coffee: [^sim]\n* `POST /session/:sessionId/appium/device/get_clipboard`\n * :octicons-check-24: Moved to drivers: :material-android: :material-coffee:\n * :octicons-arrow-right-24: `mobile: getClipboard` execute method :material-apple: :material-android: :material-coffee:\n * :octicons-arrow-right-24: `mobile: getPasteboard` execute method :material-apple: [^sim]\n * :octicons-arrow-right-24: `windows: getClipboard` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/appium/device/gsm_call`\n * :octicons-arrow-right-24: `mobile: gsmCall` execute method :material-android: [^sim] :material-coffee: [^sim]\n* `POST /session/:sessionId/appium/device/gsm_signal`\n * :octicons-arrow-right-24: `mobile: gsmSignal` execute method :material-android: [^sim] :material-coffee: [^sim]\n* `POST /session/:sessionId/appium/device/gsm_voice`\n * :octicons-arrow-right-24: `mobile: gsmVoice` execute method :material-android: [^sim] :material-coffee: [^sim]\n* `POST /session/:sessionId/appium/device/is_locked`\n * :octicons-arrow-right-24: `mobile: isLocked` execute method :material-apple: :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/keyevent`\n * :octicons-arrow-right-24: `mobile: keys` execute method :material-apple: (iPadOS only)\n * :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* :octicons-arrow-right-24: `mobile: keys` execute method :material-apple: (iPadOS only)\n * :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:\n * :octicons-arrow-right-24: `macos: keys` execute method :material-apple-finder:\n * :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/appium/device/lock`\n * :octicons-arrow-right-24: `mobile: lock` execute method :material-apple: :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/long_press_keycode`\n * :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/network_speed`\n * :octicons-arrow-right-24: `mobile: networkSpeed` execute method :material-android: [^sim] :material-coffee: [^sim]\n* `POST /session/:sessionId/appium/device/open_notifications`\n * :octicons-arrow-right-24: `mobile: statusBar` execute method :material-android: :material-coffee:\n * :octicons-arrow-right-24: `mobile: openNotifications` execute method :material-android:\n* `POST /session/:sessionId/appium/device/power_ac`\n * :octicons-arrow-right-24: `mobile: powerAC` execute method :material-android: [^sim] :material-coffee: [^sim]\n* `POST /session/:sessionId/appium/device/power_capacity`\n * :octicons-arrow-right-24: `mobile: powerCapacity` execute method :material-android: [^sim] :material-coffee: [^sim]\n* `POST /session/:sessionId/appium/device/press_keycode`\n * :octicons-arrow-right-24: `mobile: keys` execute method :material-apple: (iPadOS only)\n * :octicons-arrow-right-24: `mobile: pressKey` execute method :material-android: :material-coffee:\n * :octicons-arrow-right-24: `macos: keys` execute method :material-apple-finder:\n * :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/appium/device/send_sms`\n * :octicons-arrow-right-24: `mobile: sendSms` execute method :material-android: [^sim] :material-coffee: [^sim]\n* `POST /session/:sessionId/appium/device/set_clipboard`\n * :octicons-arrow-right-24: `mobile: setClipboard` execute method :material-apple: :material-android: :material-coffee:\n * :octicons-arrow-right-24: `mobile: setPasteboard` execute method :material-apple: [^sim]\n * :octicons-arrow-right-24: `windows: setClipboard` execute method :material-microsoft-windows:","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* :octicons-arrow-right-24: `mobile: setPasteboard` execute method :material-apple: [^sim]\n * :octicons-arrow-right-24: `windows: setClipboard` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/appium/device/shake`\n * :octicons-arrow-right-24: `mobile: shake` execute method :material-apple: [^sim]\n* `POST /session/:sessionId/appium/device/start_activity`\n * :octicons-arrow-right-24: `mobile: startActivity` execute method :material-android: :material-coffee:\n* `GET /session/:sessionId/appium/device/system_bars`\n * :octicons-arrow-right-24: `mobile: deviceScreenInfo` execute method :material-apple:\n * :octicons-arrow-right-24: `mobile: getSystemBars` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/toggle_airplane_mode`\n * :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/toggle_data`\n * :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/toggle_location_services`\n * :octicons-arrow-right-24: `mobile: toggleGps` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/toggle_wifi`\n * :octicons-arrow-right-24: `mobile: setConnectivity` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/device/unlock`\n * :octicons-arrow-right-24: `mobile: unlock` execute method :material-apple: :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/element/:elementId/value`\n * :octicons-arrow-right-24: `POST /session/:sessionId/element/:elementId/value` :simple-appium:\n* `POST /session/:sessionId/appium/element/:elementId/replace_value`\n * :octicons-arrow-right-24: `POST /session/:sessionId/element/:elementId/value` :simple-appium:\n* `POST /session/:sessionId/appium/getPerformanceData`\n * :octicons-arrow-right-24: `mobile: getPerformanceData` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/performanceData/types`\n * :octicons-arrow-right-24: `mobile: getPerformanceDataTypes` execute method :material-android: :material-coffee:\n* `POST /session/:sessionId/appium/receive_async_response`\n * :octicons-arrow-right-24: `POST /session/:sessionId/execute/async` :simple-appium:\n* `POST /session/:sessionId/appium/simulator/toggle_touch_id_enrollment`","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* :octicons-arrow-right-24: `POST /session/:sessionId/execute/async` :simple-appium:\n* `POST /session/:sessionId/appium/simulator/toggle_touch_id_enrollment`\n * :octicons-arrow-right-24: `mobile: enrollBiometric` execute method :material-apple: [^sim]\n* `POST /session/:sessionId/appium/simulator/touch_id`\n * :octicons-arrow-right-24: `mobile: sendBiometricMatch` execute method :material-apple: [^sim]\n* `POST /session/:sessionId/appium/start_recording_screen`\n * :octicons-check-24: Moved to drivers: :material-apple: :material-android: :material-coffee: :material-apple-finder: :material-microsoft-windows:\n * :octicons-arrow-right-24: `mobile: startXCTestScreenRecording` execute method :material-apple:\n * :octicons-arrow-right-24: `mobile: startMediaProjectionRecording` execute method :material-android: :material-coffee:\n * :octicons-arrow-right-24: `macos: startRecordingScreen` or `macos: startNativeScreenRecording` execute methods :material-apple-finder:\n * :octicons-arrow-right-24: `windows: startRecordingScreen` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/appium/stop_recording_screen`\n * :octicons-check-24: Moved to drivers: :material-apple: :material-android: :material-coffee: :material-apple-finder: :material-microsoft-windows:\n * :octicons-arrow-right-24: `mobile: stopXCTestScreenRecording` execute method :material-apple:\n * :octicons-arrow-right-24: `mobile: stopMediaProjectionRecording` execute method :material-android: :material-coffee:\n * :octicons-arrow-right-24: `macos: stopRecordingScreen` or `macos: stopNativeScreenRecording` execute methods :material-apple-finder:\n * :octicons-arrow-right-24: `windows: stopRecordingScreen` execute method :material-microsoft-windows:\n* `GET /session/:sessionId/application_cache/status`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `POST /session/:sessionId/buttondown`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: [W3C Actions API](https://www.selenium.dev/documentation/webdriver/actions_api/) (`pointerDown`) :simple-appium:\n * :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/buttonup`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerUp`) :simple-appium:","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* `POST /session/:sessionId/buttonup`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerUp`) :simple-appium:\n * :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/click`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:\n* `POST /session/:sessionId/dismiss_alert`\n * :octicons-arrow-right-24: `POST /session/:sessionId/alert/dismiss` :simple-appium:\n* `POST /session/:sessionId/doubleclick`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:\n* `POST /session/:sessionId/element/active`\n * :octicons-arrow-right-24: `GET /session/:sessionId/element/active` :simple-appium:\n* `GET /session/:sessionId/element/:elementId/equals/:otherId`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n* `GET /session/:sessionId/element/:elementId/location`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/rect` :simple-appium:\n* `GET /session/:sessionId/element/:elementId/location_in_view`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n* `GET /session/:sessionId/element/:elementId/pageIndex`\n * :octicons-no-entry-24: MJSONWP protocol command with no direct replacement\n* `GET /session/:sessionId/element/:elementId/size`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/rect` :simple-appium:\n* `POST /session/:sessionId/element/:elementId/submit`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `POST /session/:sessionId/execute`\n * :octicons-arrow-right-24: `POST /session/:sessionId/execute/sync` :simple-appium:\n* `POST /session/:sessionId/execute_async`\n * :octicons-arrow-right-24: `POST /session/:sessionId/execute/async` :simple-appium:\n* `POST /session/:sessionId/keys`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`keyDown` & `keyUp`) :simple-appium:","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* `POST /session/:sessionId/keys`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`keyDown` & `keyUp`) :simple-appium:\n * Selenium-based clients can also use [Send Keys](https://www.selenium.dev/documentation/webdriver/actions_api/keyboard/#send-keys)\n* `GET /session/:sessionId/local_storage`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `POST /session/:sessionId/local_storage`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `DELETE /session/:sessionId/local_storage`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `GET /session/:sessionId/local_storage/key/:key`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `DELETE /session/:sessionId/local_storage/key/:key`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `GET /session/:sessionId/local_storage/size`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `POST /session/:sessionId/log`\n * :octicons-arrow-right-24: `POST /session/:sessionId/se/log` :simple-appium:\n* `GET /session/:sessionId/log/types`\n * :octicons-arrow-right-24: `GET /session/:sessionId/se/log/types` :simple-appium:\n* `POST /session/:sessionId/moveto`\n * :octicons-arrow-right-24: W3C Actions API (`pointerMove`) :simple-appium:\n * Selenium-based clients can also use [Move by Offset](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#move-by-offset)\n* `GET /session/:sessionId/screenshot/:elementId`\n * :octicons-arrow-right-24: `GET /session/:sessionId/element/:elementId/screenshot` :simple-appium:\n* `GET /session/:sessionId/session_storage`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `POST /session/:sessionId/session_storage`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `DELETE /session/:sessionId/session_storage`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `GET /session/:sessionId/session_storage/key/:key`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `DELETE /session/:sessionId/session_storage/key/:key`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `GET /session/:sessionId/session_storage/size`","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* `DELETE /session/:sessionId/session_storage/key/:key`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `GET /session/:sessionId/session_storage/size`\n * :octicons-no-entry-24: JSONWP protocol command with no direct replacement\n* `POST /session/:sessionId/timeouts/async_script`\n * :octicons-arrow-right-24: `POST /session/:sessionId/timeouts` :simple-appium:\n* `POST /session/:sessionId/timeouts/implicit_wait`\n * :octicons-arrow-right-24: `POST /session/:sessionId/timeouts` :simple-appium:\n* `POST /session/:sessionId/touch/click`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:\n * Selenium-based clients can also use [Click and Release](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#click-and-release)\n * :octicons-arrow-right-24: `mobile: tap` or `mobile: tapWithNumberOfTaps` execute methods :material-apple:\n * :octicons-arrow-right-24: `mobile: clickGesture` execute method :material-android:\n * :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:\n * :octicons-arrow-right-24: `macos: click`, `macos: rightClick`, `macos: press` or `macos: tap` execute methods :material-apple-finder:\n * :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/touch/doubleclick`\n * :octicons-arrow-right-24: W3C Actions API (`pointerDown` & `pointerUp`) :simple-appium:\n * Selenium-based clients can also use [Double Click](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#double-click)\n * :octicons-arrow-right-24: `mobile: doubleTap` or `mobile: tapWithNumberOfTaps` execute methods :material-apple:\n * :octicons-arrow-right-24: `mobile: doubleClickGesture` execute method :material-android:\n * :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:\n * :octicons-arrow-right-24: `macos: doubleClick` or `macos: doubleTap` execute methods :material-apple-finder:\n * :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/touch/down`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerDown`) :simple-appium:\n * :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* :octicons-arrow-right-24: W3C Actions API (`pointerDown`) :simple-appium:\n * :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/touch/flick`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pointerMove` & `pointerUp`) :simple-appium:\n * :octicons-arrow-right-24: `mobile: flingGesture` execute method :material-android:\n* `POST /session/:sessionId/touch/longclick`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pause` & `pointerUp`) :simple-appium:\n * :octicons-arrow-right-24: `mobile: touchAndHold` execute method :material-apple:\n * :octicons-arrow-right-24: `mobile: longClickGesture` execute method :material-android:\n * :octicons-arrow-right-24: `mobile: clickAction` execute method :material-coffee:\n * :octicons-arrow-right-24: `macos: press` execute method :material-apple-finder:\n * :octicons-arrow-right-24: `windows: click` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/touch/multi/perform`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `POST /session/:sessionId/actions` :simple-appium:\n* `POST /session/:sessionId/touch/move`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerMove`) :simple-appium:\n * Selenium-based clients can also use [Move by Offset](https://www.selenium.dev/documentation/webdriver/actions_api/mouse/#move-by-offset)\n* `POST /session/:sessionId/touch/perform`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `POST /session/:sessionId/actions` :simple-appium:\n* `POST /session/:sessionId/touch/scroll`\n * :octicons-arrow-right-24: W3C Actions API (`pointerDown`, `pointerMove` & `pointerUp`) :simple-appium:\n * :octicons-arrow-right-24: `mobile: scroll` or `mobile: swipe` execute methods :material-apple:\n * :octicons-arrow-right-24: `mobile: scrollGesture` or `mobile: swipeGesture` execute methods :material-android:\n * :octicons-arrow-right-24: `mobile: swipe` execute method :material-coffee:\n * :octicons-arrow-right-24: `macos: scroll` or `macos: swipe` execute methods :material-apple-finder:","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Removed\n\n* :octicons-arrow-right-24: `mobile: swipe` execute method :material-coffee:\n * :octicons-arrow-right-24: `macos: scroll` or `macos: swipe` execute methods :material-apple-finder:\n * :octicons-arrow-right-24: `windows: scroll` execute method :material-microsoft-windows:\n* `POST /session/:sessionId/touch/up`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: W3C Actions API (`pointerUp`) :simple-appium:\n * :octicons-arrow-right-24: `windows: keys` execute method :material-microsoft-windows:\n* `GET /session/:sessionId/window_handle`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `GET /session/:sessionId/window` :simple-appium:\n* `GET /session/:sessionId/window_handles`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `GET /session/:sessionId/window/handles` :simple-appium:\n* `GET /session/:sessionId/window/handle`\n * :octicons-arrow-right-24: `GET /session/:sessionId/window` :simple-appium:\n* `POST /session/:sessionId/window/:windowhandle/maximize`\n * :octicons-arrow-right-24: `POST /session/:sessionId/window/maximize` :simple-appium:\n * :fontawesome-solid-triangle-exclamation: Only supported for the current window\n* `GET /session/:sessionId/window/:windowhandle/position`\n * :octicons-arrow-right-24: `GET /session/:sessionId/window/rect` :simple-appium:\n * :fontawesome-solid-triangle-exclamation: Only supported for the current window\n* `POST /session/:sessionId/window/:windowhandle/position`\n * :octicons-arrow-right-24: `POST /session/:sessionId/window/rect` :simple-appium:\n * :fontawesome-solid-triangle-exclamation: Only supported for the current window\n* `GET /session/:sessionId/window/:windowhandle/size`\n * :octicons-check-24: Moved to drivers: :material-microsoft-windows:\n * :octicons-arrow-right-24: `GET /session/:sessionId/window/rect` :simple-appium:\n * :fontawesome-solid-triangle-exclamation: Only supported for the current window","metadata":{"headerPath":"## Endpoint Changes > ### Removed","sectionCount":1,"recursiveSplit":true,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"## Endpoint Changes > ### Modified\n\nThe following are all endpoints modified in Appium 3, by removing handling for old or unused\nparameters (note that no new parameters have been added). Each endpoint lists the parameters it no\nlonger accepts, as well as the parameters it continues to accept in Appium 3.\n\n* `POST /session`\n * :octicons-x-24: `desiredCapabilities`, `requiredCapabilities`\n * :octicons-check-24: `capabilities`\n* `POST /session/:sessionId/alert/text`\n * :octicons-x-24: `value`\n * :octicons-check-24: `text`\n* `GET /session/:sessionId/appium/device/system_time`\n * :octicons-x-24: `format`\n * :octicons-check-24: None\n* `POST /session/:sessionId/element/:elementId/value`\n * :octicons-x-24: `value`\n * :octicons-check-24: `text`\n* `POST /session/:sessionId/timeouts`\n * :octicons-x-24: `type`, `ms`\n * :octicons-check-24: `script`, `pageLoad`, `implicit`\n* `POST /session/:sessionId/window`\n * :octicons-x-24: `name`\n * :octicons-check-24: `handle`\n\n[^sim]: Supported in emulators/simulators only","metadata":{"headerPath":"## Endpoint Changes > ### Modified","sectionCount":1,"filename":"migrating-2-to-3.md","relativePath":"appium/packages/appium/docs/en/guides/migrating-2-to-3.md"}},{"pageContent":"---\ntitle: Appium Server Security\n---\n\nThe Appium team makes every effort to ensure the security of the Appium server. This is especially\nimportant when Appium is run in a multitenant environment, or when multiple users are running\nsessions on the same Appium server. In general, you can only safely enable all Appium's features if\nall the following are true:\n\n- You're running your own Appium server locally or within a protected internal network\n- You're not sharing it with any untrusted parties\n- You don't expose Appium's port(s) to the wider internet\n\nBut because many Appium users might not be able to guarantee such a safe environment, the Appium\nteam puts many features behind a security protection mechanism which forces system admins (the\npeople that are in charge of starting the Appium server) to _explicitly opt-in_ to these features.\n(Third-party driver and plugin authors can also [hide behaviour behind security\nflags](../developing/build-drivers.md).)\n\nFor security reasons, Appium client sessions can _not_ request feature enablement via capabilities;\nthis is the responsibility of the server admin who configures and launches the Appium server.","metadata":{"headerPath":"","sectionCount":1,"filename":"security.md","relativePath":"appium/packages/appium/docs/en/guides/security.md"}},{"pageContent":"## Security Server Args\n\nThe [Server CLI](../reference/cli/server.md) doc outlines three relevant arguments which may be passed to\nAppium when starting it from the command line:\n\n|<div style=\"width:10em\">Parameter</div>|Description|\n|---------------------------------------|-----------|\n|`--relaxed-security`|Turns on _all_ insecure features, except those blocked by `--deny-insecure`|\n|`--allow-insecure`|Turns on _only_ specified features, except those blocked by `--deny-insecure`. Has no effect when used in combination with `--relaxed-security`|\n|`--deny-insecure`|Explicitly turns _off_ specified features, overriding `--relaxed-security` and `--allow-insecure`|\n\nAll of the above arguments can also be specified in the [Appium Configuration file](./config.md).\n\nFeatures passed to `--allow-insecure`/`--deny-insecure` must be specified as a comma-separated list,\nand each feature in the list must additionally include a prefix, indicating the driver to which the\nfeature should apply. The prefix can be either the driver's `automationName`, or the wildcard (`*`)\nsymbol, if the feature should be applied to all drivers. The prefix and feature name are separated\nusing the colon character (`:`).\n\nFor example, `first:foo` refers to the `foo` feature for the `first` driver, whereas `*:bar` refers\nto the `bar` feature for all drivers.","metadata":{"headerPath":"## Security Server Args","sectionCount":1,"filename":"security.md","relativePath":"appium/packages/appium/docs/en/guides/security.md"}},{"pageContent":"## Insecure Features\n\nEach Appium driver is responsible for its own security, and can create its own feature names. Thus\nyou should read through the documentation for a particular driver to know which feature names it\nmight use. Here is an incomplete list of examples from some of Appium's official drivers:\n\n|<div style=\"width:12em\">Feature Name</div>|Description|Supported Extension(s)|\n|------------|-----------|-------|\n|`get_server_logs`|Allows retrieving of Appium server logs via the Webdriver log interface|IOS, XCUITest, Android, UiAutomator2, Espresso|\n|`adb_shell`|Allows execution of arbitrary shell commands via ADB, using the `mobile: shell` command|Android, UiAutomator2, Espresso|\n|`record_audio`|Allow recording of host machine audio inputs|XCUITest|\n|`execute_driver_script`| Allows to send a request which has multiple Appium commands.|Execute Driver Plugin|\n\nSome insecure features operate on the server level, and do not require a driver session. Enabling\nthese features requires using the wildcard prefix:\n\n|<div style=\"width:12em\">Feature Name</div>|Description|\n|------------|-----------|\n|`session_discovery`|Allows retrieving the list of active server sessions via `GET /appium/sessions`|\n\n## Examples\n\nTurn on the `foo` feature only for the `first` driver:\n\n```bash\nappium --allow-insecure=first:foo\n```\n\nTurn on the `foo` feature for all drivers:\n\n```bash\nappium --allow-insecure=*:foo\n```\n\nTurn on the `foo` feature for all drivers _except_ `first`:\n\n```bash\nappium --allow-insecure=*:foo --deny-insecure=first:foo\n```\n\nTurn on all features _except_ `foo` for all drivers:\n\n```bash\nappium --relaxed-security --deny-insecure=*:foo\n```","metadata":{"headerPath":"## Insecure Features","sectionCount":2,"filename":"security.md","relativePath":"appium/packages/appium/docs/en/guides/security.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Session Settings\n---\n\nAppium has a set of extension APIs that allow you to adjust parameters for a given session during\nthe session itself. Called \"Settings\", these parameters are similar to [Capabilities](./caps.md),\nbut while Capabilities _cannot be adjusted_ once a session has started, Settings _can be adjusted any\nnumber of times_ during the course of a session.\n\nThere are 3 important points to the concept of Settings:\n\n- Settings are mutable; they can be changed during a session using the Settings API\n- Settings are only relevant during the session in which they are set. They are typically reset for\n each new session, though depending on the driver, some settings may persist between sessions\n- Settings only adjust the way the Appium server behaves during test automation. They do not affect\n the device or app under test\n\nAn example of a setting would be the `ignoreUnimportantViews` setting recognized by the UiAutomator2\ndriver. The driver can be instructed to ignore elements in the view hierarchy which it deems\nirrelevant. Changing this setting to `true` can cause tests to run faster. But if later in the same\nsession you _want_ to access elements which would be ignored under this setting, you can always\nchange it back to `false`.\n\nSettings are implemented via the following API endpoints:\n\n| Command | <div style=\"width:18em\">Method/Route</div> | Params | Description | Returns |\n|-------------------|---------------------------------------------|------------------------------------|------------------------------------|------------------------------------|\n| `Update Settings` | `POST /session/:id/appium/settings` | `settings` (`Record<string, any>`) | Update the provided setting values | `null` |\n| `Get Settings` | `GET /session/:id/appium/settings` | | Return the current settings | `settings` (`Record<string, any>`) |\n\nThe `settings` object must be a set of keys and values, where the key is the setting name, and the\nvalue is any documented valid value for that setting.\n\n!!! info\n\n Settings are driver-specific, so refer to your driver's documentation for a list of supported settings","metadata":{"headerPath":"","sectionCount":1,"filename":"settings.md","relativePath":"appium/packages/appium/docs/en/guides/settings.md"}},{"pageContent":"## Initializing Settings via Capabilities\n\nIf you want to start an Appium session with a setting in a non-default state, you can do so by\nincluding a capability of the form `appium:settings[<name>]` with the appropriate value. So to turn\non the `ignoreUnimportantViews` setting mentioned above from the very beginning of a session, you\nwould construct a set of capabilities that includes the following in its JSON representation:\n\n```json\n{\n \"appium:settings[ignoreUnimportantViews]\": true\n}\n```\n\nAlso, since Appium 2.1, there is a possibility to provide multiple settings in a single\n`appium:settings` capability value:\n\n```json\n{\n \"appium:settings\": {\n \"ignoreUnimportantViews\": true,\n \"allowInvisibleElements\": true\n }\n}\n```\n\nOf course, initializing a setting via capabilities doesn't prevent you from changing it later on\nvia the Settings API. To learn more about how to use the Settings API in the context of your\nspecific client library, visit the documentation for that client.","metadata":{"headerPath":"## Initializing Settings via Capabilities","sectionCount":1,"filename":"settings.md","relativePath":"appium/packages/appium/docs/en/guides/settings.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: SSL/TLS/SPDY Support\n---\n\nAppium 2.2 introduces the option to start the Appium server with SSL/TLS support.\n\n## Command Line Arguments\n\nIn order to enable secure connections to the server, you need to provide the following command\nline arguments:\n\n```bash\nappium server --ssl-cert-path=/path/to/cert.pem --ssl-key-path=/path/to/key.pem\n```\n\nBoth arguments must be provided and should contain paths to a valid\n[X509 PEM](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/)\ncertificate and its corresponding private key.\n\nAfter the server is started use the `https` protocol and a client supporting SSL/TLS or\n[SPDY](https://en.wikipedia.org/wiki/SPDY) to communicate to it.\n\n## Command Line Arguments > ### Supported Features\n\nOnce a secure server socket is established it supports the following protocols:\n`['h2', 'spdy/3.1', 'spdy/3', 'spdy/2', 'http/1.1', 'http/1.0']`. See\n[the SPDY node module documentation](https://www.npmjs.com/package/spdy) to get more details about\nits features. All insecure client connections will be rejected by the server.\n\n## Command Line Arguments > ### Self-Signed Certificates\n\nUse the following command in order to generate a self-signed certificate/key pair:\n\n```bash\nopenssl req -nodes -new -x509 -keyout key.pem -out cert.pem -subj \"/C=US/ST=State/L=City/O=company/OU=Com/CN=www.testserver.local\"\n```\n\nFeel free to change the value of `-subj` in the command above with your matching details. The server\nshould work just fine with a self-signed certificate, although you need to take care about a proper\nclient setup, e.g. make sure it does not reject unauthorized certificates.","metadata":{"headerPath":"","sectionCount":4,"filename":"tls.md","relativePath":"appium/packages/appium/docs/en/guides/tls.md"}},{"pageContent":"---\nhide:\n - navigation\n - toc\n\ntitle: Welcome\n---\n<style>\n .md-typeset h1,\n .appium-sponsor-thanks {\n display: none;\n }\n</style>\n\n<div style=\"text-align: center\">\n <img src=\"assets/images/appium-logo-horiz.png\" style=\"max-width: 400px;\" />\n</div>\n\nWelcome to the Appium documentation! Appium is an open-source project and ecosystem of related\nsoftware, designed to facilitate UI automation of many app platforms, including mobile (iOS,\nAndroid, Tizen), browser (Chrome, Firefox, Safari), desktop (macOS, Windows), TV (Roku, tvOS,\nAndroid TV, Samsung), and more!\n\n\n<div style=\"text-align: center; margin-top: 2rem; font-style: italic;\">\n Appium is extremely grateful for the support of its key partners! (Learn more about our\n sponsorship program and contributor compensation scheme <a\n href=\"https://github.com/appium/appium/blob/master/GOVERNANCE.md#sponsorship\">here</a>)\n <div class=\"homepageSponsors\">\n <div class=\"homepageSponsor\">\n <a href=\"https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium\">\n <img src=\"assets/images/sponsor-logo-browserstack-dark.png#only-dark\" style=\"width: 220px;\" />\n <img src=\"assets/images/sponsor-logo-browserstack-light.png#only-light\" style=\"width: 220px;\" />\n </a>\n </div>\n <div class=\"homepageSponsor\">\n <a href=\"https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage\">\n <img src=\"assets/images/sponsor-logo-lambdatest-dark.png#only-dark\" style=\"width: 220px;\" />\n <img src=\"assets/images/sponsor-logo-lambdatest-light.png#only-light\" style=\"width: 220px;\" />\n </a>\n </div>\n </div>\n</div>","metadata":{"headerPath":"","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/index.md"}},{"pageContent":"## Explore the Documentation\n\n<div class=\"grid cards\" markdown>\n\n- Check out the [__Introduction__](./intro/index.md) to make sure you understand the key concepts\n- Go through the [__Quickstart__](./quickstart/index.md) to get set up and run a basic Android test\n- Visit the [__Ecosystem__](./ecosystem/index.md) page for a list of drivers, clients and plugins you may want to use\n- Consult the [__Reference__](./reference/index.md) page for information on the Appium CLI and supported endpoints\n- Read the different [__Guides__](./guides/migrating-2-to-3.md) for a variety of instructions, tips and tricks\n- Check out various third-party [__Resources__](./resources/index.md) to explore Appium around the web\n- For creating your own Appium extensions, see the [__Developer__](./developing/index.md) documentation\n- For contributions to Appium itself, refer to the [__Contributing__](./contributing/index.md) page\n- Have a look at the [__Appium Blog__](./blog/index.md) to learn what's new in the project\n\n</div>","metadata":{"headerPath":"## Explore the Documentation","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/index.md"}},{"pageContent":"---\ntitle: How Does Appium Work?\n---\n\nAs mentioned on the main page, Appium is an open-source project and ecosystem of related software,\ndesigned to facilitate UI automation of many app platforms. With the release of Appium 2, Appium\nhas the following primary goals:[^1]\n\n- Make platform-specific automation capabilities available under a cross-platform, standard API\n- Allow easy access to this API from any programming language\n- Provide tools to enable convenient community development of Appium extensions\n\n[^1]:\n To meet these primary goals, we also work with a set of secondary goals or methodology\n principles, which we also encourage for Appium extension developers:\n\n - As far as possible, rely on (and contribute to) open source technology\n - As far as possible, rely on vendor-provided tools for a given platform\n - As far as possible, rely on automation tools that allow automation of unmodified apps (prefer\n not to require the user to build in additional SDKs or software that introduce discrepancies\n between the test version of the app and the production version)\n - As far as possible, rely on existing standards instead of creating new ones\n\nSo, take any app platform you know about, like iOS or Android. Appium wants for there to be a way\nfor developers and testers to write UI automation code for that platform, according to a single,\nunified API. Based on Appium's goals, we have a lot of questions to answer to make it all work:\n\n- Which API should that \"single, unified\" API be?\n- How do we map that API to automation behaviour for a specific platform?\n- How do we make that API accessible via multiple popular programming languages?\n\nThere's another, larger, question lurking in the background here too, given that there are more app\nplatforms out there than just iOS and Android:\n\n- How do we enable automation for *all* the platforms?\n\nExploring Appium's answers to these questions may not be the quickest way to learn what Appium is,\nbut it is certainly a good one! So let's dive in.","metadata":{"headerPath":"","sectionCount":1,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/intro/appium.md"}},{"pageContent":"## Appium's choice of API\n\nAppium is very fortunate to have been preceded by a technology which has been a long-standing\npioneer in the field of UI automation, namely [Selenium](https://selenium.dev). The goal of the\nSelenium project has been to support UI automation of web browsers, and in this way we can think of\nit as occupying a subset of Appium's goals. Along the way, Selenium (and, after they merged,\nanother project called WebDriver) developed a relatively stable API for browser automation.\n\nOver the years, Selenium worked with various web browser vendors and the [W3C](https://w3.org)\nstandards group to turn its API into an official web browser standard, called the [WebDriver\nspecification](https://w3c.github.io/webdriver/). All the main browsers now\nimplement automation capabilities inline with the WebDriver spec, without the Selenium team having\nto maintain any software that performs actual automation; standards for the win!\n\nAppium's initial goals were to develop an automation standard for mobile apps (iOS and Android). We\ncould have made up something new, but in the spirit of joining forces and keeping standards, well,\nstandard, we decided to adopt the WebDriver spec as Appium's API.[^2] While user interaction on\nwebsites and in mobile native apps are not entirely identical (with even greater differences once\nwe start to consider, for example, TV platforms controlled by simple remotes), the fact is that\nmost software UIs are pretty much the same. This means that the WebDriver spec provides automation\nAPI primitives (finding elements, interacting with elements, loading pages or screens, etc...) that\nmore or less map to any platform.\n\n[^2]: Technically, when Appium was first written, we were dealing with something older than the\n WebDriver spec, called the JSON Wire Protocol. Since then, Appium continued to evolve along with\n the W3C spec and is fully W3C-compliant.\n\nOf course, Appium wants to support the cases where user interaction *does* differ from web to\nmobile or web to TV, and so Appium also makes use of the built-in *extensibility* of the WebDriver\nspec. The result is that, no matter what platform you want to automate, when you use Appium, you\nwill do so using the standard WebDriver spec, with two caveats:","metadata":{"headerPath":"## Appium's choice of API","sectionCount":1,"recursiveSplit":true,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/intro/appium.md"}},{"pageContent":"## Appium's choice of API\n\n- We might not have any way to support a particular WebDriver API command on a given platform, and\n so some commands might be unsupported (for example, getting or setting cookies is not possible in\n the world of native mobile app automation).\n- We might support automation behaviours that go *beyond* what's available in the WebDriver API\n command list, though any such commands will be valid and spec-compliant extensions to the\n WebDriver API.\n\nHow do you actually *use* the WebDriver API, particularly in the context of Appium? We'll cover\nthat in the [section below](#universal-programming-language-access) on how Appium provides\nuniversal programming language access. All you need to know for now is that the way Appium\nintroduces a universal UI automation interface is by implementing the WebDriver protocol.","metadata":{"headerPath":"## Appium's choice of API","sectionCount":1,"recursiveSplit":true,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/intro/appium.md"}},{"pageContent":"## Platform automation behaviour\n\nThe next question is, how does Appium map this protocol to automation behaviour on a wide range of\nplatforms? The trick is that, strictly speaking, Appium doesn't! It leaves this responsibility up\nto a kind of software module called an Appium *driver*. There's a whole [Driver\nIntroduction](./drivers.md) which you can read next, so we won't go into huge detail on how they\nwork for now.\n\nWhat's important to understand at the moment is that a driver is kind of like a pluggable module\nfor Appium that gives Appium the power to automate a particular platform (or set of platforms,\ndepending on the goal of the driver). At the end of the day, a driver's responsibility is to simply\nimplement an Appium-internal interface representing the WebDriver protocol. How it implements this\ninterface is totally up to the driver, based on its strategy for making automation happen on\na specific platform. Typically, and with a lot more complexity and difficulty in the details,\na driver does this by relying on platform-specific automation technologies. For example, Apple\nmaintains an iOS automation technology called\n[XCUITest](https://developer.apple.com/documentation/xctest/user_interface_tests). The Appium\ndriver that supports iOS app automation is called the [XCUITest\nDriver](https://github.com/appium/appium-xcuitest-driver) because ultimately what it does is\nconvert the WebDriver protocol to XCUITest library calls.\n\nOne of the reasons that drivers are independent, pluggable modules is that they work completely\ndifferently from one another. The tools and requirements for building and using drivers for\ndifferent platforms are completely different. And so Appium lets you use just the drivers that you\nneed for your automation tasks. Choosing drivers and installing them so that you can use them with\nyour Appium instance is so important that Appium has its very own [CLI for managing\ndrivers](../reference/cli/extensions.md).\n\nSo, to answer our original question, the way that Appium provides access to automation capabilities\nfor a given platform is that the Appium team (or anyone else[^3]) writes a *driver* for that\nplatform, implementing as much or little of the WebDriver protocol as desired. The driver can then\nbe installed by anyone using Appium.\n\n[^3]: You can build and share your own drivers! Check out [Building\n Drivers](../developing/build-drivers.md) to learn more about how to develop drivers in Node.js\n that can be used with Appium.","metadata":{"headerPath":"## Platform automation behaviour","sectionCount":1,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/intro/appium.md"}},{"pageContent":"## Universal programming language access\n\nBut what does it mean, or look like, to *use* Appium, anyway? Since Appium is ultimately a Node.js\nprogram, it *could* have looked like importing Appium and its drivers as libraries into your own\nNode.js programs. But that wouldn't meet Appium's goal of providing automation capabilities to\npeople using any popular programming language.\n\nLuckily, the fact that Appium rode in on Selenium's coattails meant that we had a solution to this\nproblem from day one. You see, the WebDriver specification is actually an HTTP-based protocol,\nmeaning it is designed to be used over a network rather than within the memory of a single program.\n\nOne of the main benefits of this \"client-server\" architecture is that it allows the automation\nimplementer (the thing doing the automation, in this case the 'server') to be completely distinct\nfrom the automation runner (the thing defining what automation should be done, in what steps,\netc..., in this case the 'client'). Basically, all the \"hard stuff\" (actually figuring out how to\nmake automation happen on a given platform) can be handled in one place by the server, and \"thin\"\nclient libraries can be written in any programming language which simply encode HTTP requests to\nthe server in language-appropriate way. It's possible, in other words, to bring basic Appium\n/ WebDriver capabilities to a new programming language relatively easily, assuming high-level HTTP\nlibraries exist, simply by coding up a basic HTTP client in that language.\n\nThere are a couple important takeaways here for you, the Appium user:","metadata":{"headerPath":"## Universal programming language access","sectionCount":1,"recursiveSplit":true,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/intro/appium.md"}},{"pageContent":"## Universal programming language access\n\nThere are a couple important takeaways here for you, the Appium user:\n\n- Appium is an *HTTP server*. It must run as a process on some computer for as long as you want to\n be able to use it for automation. It must be accessible on the network to whichever computer you\n want to use to run the automation from (whether that is the same machine or one across the\n world).\n- Unless you want to write raw HTTP calls or use cURL, using Appium for automation involves the use\n of an [Appium Client](clients.md) in the language of your choice. The goal of each of these\n clients is to encapsulate the WebDriver protocol so that rather than worrying about the protocol\n itself, you can work with objects and methods that feel idiomatic for your language.\n- The Appium server and the Appium client do *not* need to be running on the same computer. You\n simply need to be able to send HTTP requests from the client to the server over some network.\n This greatly facilitates the use of cloud providers for Appium, since they can host the Appium\n server and any related drivers and devices, and all you need to do is point your client script to\n their secure endpoints.\n\nAnd of course, none of this is about \"testing\" per se, purely about the use of Appium and its\nclient libraries for automation purposes. If you want to do automation for the purpose of\n\"testing\", you'll likely want to enlist the help of test runners, test frameworks, and the like,\nnone of which need be related to Appium; one of the benefits of Appium's \"universal accessibility\"\nis that it plays well with whatever set of tools you find most beneficial for your situation.","metadata":{"headerPath":"## Universal programming language access","sectionCount":1,"recursiveSplit":true,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/intro/appium.md"}},{"pageContent":"## Appium's huge scope\n\nAppium's vision (automation of everything under a single API) is huge! Certainly, much bigger than\nthe team of core maintainers for the open source project. So how does Appium hope to achieve this\ngoal? Basically, by empowering the community to develop functionality on top of Appium as\na *platform*. This is what we call the Appium \"ecosystem\".\n\nThe Appium team does officially maintain a few drivers itself (for example, the XCUITest driver\nthat we spoke about earlier). But it cannot hope to have the platform-specific expertise or the\ncapacity to maintain drivers for many different platforms. But what we have done, particularly\nbeginning with Appium 2, is to provide tools to empower the community to join in our vision:\n\n- Anyone can create a driver simply by creating a Node.js module that conforms to the appropriate\n conventions and implements any (sub|super)set of the WebDriver protocol. Creating a driver often\n involves a minimal amount of code because the WebDriver protocol details are abstracted away, and\n many helper libraries are available---the same libraries that power the Appium team's own\n drivers.\n- Sharing drivers with others is easy using the Appium driver CLI. There is no central authority.\n Anyone can share drivers publicly or privately, for free or for sale. Drivers can be open or\n closed source (though obviously we appreciate open source!).\n\nAppium's vision of being a platform for development extends beyond the support of automation for\nall app platforms. As a popular automation tool, there are many opportunities for integrating\nAppium with all kinds of other tools and services. In addition, there are many feature ideas for\nAppium, either as a core server or in its incarnation across various drivers, which the core team\nwill never have time to build. And so, with Appium 2, Appium has released a plugin system that\nenables anyone to build and share modules that change how Appium works!","metadata":{"headerPath":"## Appium's huge scope","sectionCount":1,"recursiveSplit":true,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/intro/appium.md"}},{"pageContent":"## Appium's huge scope\n\nIn the same way that drivers are easily shareable and consumable via the Appium driver CLI, plugins\ncan be published and consumed via a parallel [Plugin CLI](../reference/cli/extensions.md). Plugins\ncan do all sorts of things, for example adding the ability for Appium to find and interact with\nscreen regions based on a template image (as in the [`images`\nplugin](https://github.com/appium/appium/tree/master/packages/images-plugin)). There are very few\nlimitations on what you can do with plugins, so you might also be interested in learning how to\n[Build Plugins](../developing/build-plugins.md) in Node.js that can be used with Appium.\n\nSo that's Appium: an extensible, universal interface for the UI automation of potentially\neverything! Read on into some of the specific intro docs for more details, or check out the various\nguides to dive into some more general concepts and features of Appium.","metadata":{"headerPath":"## Appium's huge scope","sectionCount":1,"recursiveSplit":true,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/intro/appium.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Intro to Appium Clients\n---\n\nFor all the reasons discussed in the [main Overview](./appium.md), Appium is based on the [W3C\nWebDriver specification](https://w3c.github.io/webdriver/). This means that\nAppium implements a client-server architecture. The server (consisting of Appium itself along with\nany drivers or plugins you are using for automation) is connected to the devices under test, and\nis actually responsible for making automation happen on those devices. The client (driven by *you*,\nthe Appium test author) is responsible for sending commands to the server over the network, and\nreceiving responses from the server as a result. These responses can be used to tell whether\nautomation commands are successful, or might contain information that you queried about the state\nof the application. This document is a conceptual introduction to the client side of this equation.\n\n!!! info\n\n For more about the server side of the equation (i.e., how does Appium actually control\n devices?), check out our [Intro to Appium Drivers](./drivers.md). To skip to a list of links to\n Appium client libraries, check out the [list of clients](../ecosystem/clients.md).\n\nWhat sorts of automation commands are available? That is up to the particular driver and plugins\nthat you are using in any given session. A standard set of commands would include, for example, the\nfollowing:\n\n- Find Element\n- Click Element\n- Get Page Source\n- Take Screenshot\n\nIf you look at these commands in the WebDriver specification, you'll notice that they are not\ndefined in terms of any particular programming language. They are not Java commands, or JavaScript\ncommands, or Python commands. Instead, they form part of an HTTP API which can be accessed from\nwithin *any* programming language (or none! you could just use cURL if you want).\n\nSo, for example, the `Find Element` command corresponds to an HTTP `POST` request sent to the HTTP\nendpoint `/session/:sessionid/element` (where in this case, `:sessionid` is a placeholder for the\nunique session ID generated by the server in a previous call to `Create Session`).","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"clients.md","relativePath":"appium/packages/appium/docs/en/intro/clients.md"}},{"pageContent":"This information is primarily useful for people developing technology that works with the WebDriver\nspec. It's not particularly useful for people trying to write Appium or Selenium tests. When you\nwrite an Appium test, you want to use a programming language you're familiar with. Luckily, there\nexist a set of [Appium client libraries](../ecosystem/clients.md)[^1] that take care of the\nresponsibility of speaking HTTP to the Appium server. Instead, they expose a set of \"native\"\ncommands for a particular programming language, so that, to the test author, it just feels like\nyou're writing Python, or JavaScript, or Java.\n\nAs an example, here's the same simple set of Appium commands in five different programming\nlanguages, using the recommended Appium client binding for each language (note that this is not\nworking sample code including all appropriate imports; see each client library's instructions for\nsetup and command reference):\n\n=== \"JavaScript (Webdriver.io)\"\n\n ```js\n const element = await driver.$('//*[@text=\"Foo\"]');\n await element.click();\n console.log(await element.getText())\n console.log(await driver.getPageSource())\n ```\n\n=== \"Java\"\n\n ```java\n WebElement element = driver.findElement(By.Xpath(\"//*[@text='Foo']\"))\n element.click()\n System.out.println(element.getText())\n System.out.println(driver.getPageSource())\n ```\n\n=== \"Python\"\n\n ```py\n element = driver.find_element(by=By.XPATH, value='//*[@text=\"Foo\"]')\n element.click()\n print(element.text)\n print(driver.page_source)\n ```\n\n=== \"Ruby\"\n\n ```rb\n element = driver.find_element :xpath, '//*[@text=\"Foo\"]'\n element.click\n puts element.text\n puts driver.page_source\n ```\n \n=== \"C#\"\n\n ```dotnet\n AppiumElement element = driver.FindElement(MobileBy.AccessibilityId(\"Views\")); \n element.click();\n System.Console.WriteLine(element.Text);\n System.Console.WriteLine(driver.PageSource);\n ```\n \nEach of these scripts, despite being in different languages, does the same thing under the hood:","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"clients.md","relativePath":"appium/packages/appium/docs/en/intro/clients.md"}},{"pageContent":"1. Call `Find Element` with a `using` parameter of `xpath` and a `value` parameter expressing the\n XPath query used to find an element. (If you're confused about these terms, you might find an\n introduction to Appium or Selenium useful)\n2. Call `Click Element` with the ID of the element found in the previous call.\n3. Call `Get Element Text` with the ID of the same element, and print it to the console.\n4. Call `Get Page Source` to retrieve the page/app source and print it to the console.\n\nThe only other thing to keep in mind before choosing or using a client is that each client is\nindependently maintained. Just because a feature is available in one client, it doesn't mean it's\navailable in another client (though all clients support at least the standard W3C protocol plus any\ncommon appium extensions). Just because one client has a nice set of helper functions, doesn't mean\nanother will. Some clients are kept very frequently up to date, and others are not! So when\nthinking about choosing a library, the first consideration is the language you want to use, and the\nsecond consideration is how full-featured and well-maintained the library is!\n\nTo learn how to use an Appium client, visit that client's homepage to learn more. In many cases,\nthe Appium client for a given language is built *on top of* the *Selenium* client for that\nlanguage, and so certain Appium clients may only document the features which the Appium client\nadded on top of the Selenium client. All that to say, for a full reference, you may need to visit\nboth the Appium client documentation as well as the Selenium client documentation.\n\nThat's all you need to know about Appium clients! Head over to the\n[Clients](../ecosystem/clients.md) page to check out the current list of clients.\n\n[^1]: These libraries are alternately called \"clients\", \"client libraries\", or \"client bindings\".\n They all mean the same thing!","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"clients.md","relativePath":"appium/packages/appium/docs/en/intro/clients.md"}},{"pageContent":"---\ntitle: Intro to Appium Drivers\n---\n\nAs the [main Overview](./appium.md) makes clear, \"drivers\" are basically Appium's answer to the\nquestion, \"how do we support automation of multiple, unrelated platforms?\" In this doc we'll get\ninto a little more detail about how drivers work. The specific details of how drivers work probably\ndon't matter too much for you, unless you're planning on writing your own driver or contributing to\nan existing driver (things we hope you do!).\n\nThe main benefit in understanding a bit more of how drivers work is that being aware of the typical\ncomplexity or the typical driver architecture will inform your debugging process when you\ninevitably run into an issue in one of your tests.","metadata":{"headerPath":"","sectionCount":1,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/intro/drivers.md"}},{"pageContent":"## Interface Implementations\n\nAt the most basic level, drivers are simply Node.js classes that extend a special class included in\nAppium, called `BaseDriver`. You could have something very close to a \"working\" driver, with these\nvery simple lines of code:\n\n```js\nimport BaseDriver from '@appium/base-driver'\n\nclass MyNewDriver extends BaseDriver {\n}\n```\n\nThis empty driver doesn't *do* anything, but you could wrap it up in a Node.js module, add a few\nAppium-related fields to the module's manifest (`package.json`), and then install it using `appium\ndriver install`.\n\nSo, from a technical perspective, an Appium driver is just a bit of code that inherits from some\nother Appium code. That's it! Now, inheriting from `BaseDriver` actually gives us a lot, because\n`BaseDriver` is essentially an encapsulation of the entire WebDriver protocol. So all a driver\nneeds to do something useful is to *implement* Node.js methods with names corresponding to\ntheir WebDriver protocol equivalents.\n\nSo let's say I wanted to do something with this empty driver; first I have to decide which\nWebDriver command I want to implement. For our example, let's take the [Navigate\nTo](https://w3c.github.io/webdriver/#navigate-to) WebDriver command. Leave aside for the moment\nwhat I want to have the driver *do* when this command is executed. To tell Appium the driver can\nhandle the command, all we have to do is define a method like this in our driver class:[^1]\n\n```js\nasync setUrl(url) {\n // do whatever we want here\n}\n```\n\n[^1]: You might notice that `setUrl` doesn't look anything like `Navigate To`, so how did we know\n to use it rather than some other random string? Well, Appium's WebDriver-protocol-to-method-name\n mapping is defined in a special file within the `@appium/base-driver` package called\n [routes.js](https://github.com/appium/appium/blob/master/packages/base-driver/lib/protocol/routes.js).\n So if you're writing a driver, this is where you would go to figure out what method names to use\n and what parameters to expect. Or you could look at the source for any of the main Appium\n drivers!\n\nThat's it! How we actually implement the command is totally up to us, and depends on the\nplatform(s) we want to support. Here are some different example implementations of this command for\ndifferent platforms:","metadata":{"headerPath":"## Interface Implementations","sectionCount":1,"recursiveSplit":true,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/intro/drivers.md"}},{"pageContent":"## Interface Implementations\n\n- Browsers: execute some JavaScript to set `window.location.href`\n- iOS apps: launch an app using a deep link\n- Android apps: launch an app using a deep link\n- React apps: load a specific route\n- Unity: go to a named scene\n\nSo you can see there can be a lot of differences between how drivers implement the same WebDriver\ncommand across platforms.[^2] What is the *same*, though, is how they express that they can handle\na protocol command.\n\n[^2]: Of course, we want to keep the semantics as similar as possible, but in the world of iOS, for\n example, launching an app via a deep link (a URL with a special app-specific scheme) is about as\n close as we are going to get to navigating to a web URL.\n\nWe're going into this great amount of detail (which you don't need to remember, by the way),\nbecause it's important to stress the point that an Appium driver is not inherently anything in\nparticular, other than a bit of JS code that can handle WebDriver protocol commands. Where you go\nfrom there is up to you, the driver author!","metadata":{"headerPath":"## Interface Implementations","sectionCount":1,"recursiveSplit":true,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/intro/drivers.md"}},{"pageContent":"## Automation mapping\n\nBut *typically* what driver authors want to do is to provide automation behaviours for a given\nplatform(s) that are semantically very similar to the the WebDriver spec implementations for\nbrowsers. When you want to find an element, you should get a reference to a UI element. When you\nwant to click or tap that element, the resulting behaviour should be the same as if a person were\nto click or tap on the element. And so on.\n\nSo the real challenge for driver authors is not how to work with the WebDriver protocol (because\n`BaseDriver` encapsulates all that for you), but how to make the actual automation happen on the\ntarget platform. Every driver relies on its own set of underlying technologies here. As mentioned\nin the [Overview](index.md), the iOS driver uses an Apple technology called\n[XCUITest](https://developer.apple.com/documentation/xctest/xcuielement). These underlying\nautomation technologies usually have proprietary or idiosyncratic APIs of their own. Writing\na driver becomes the task of mapping the WebDriver protocol to this underlying API (or sometimes\na set of different underlying APIs--for example, the UiAutomator2 driver relies not only on the\n[UiAutomator2](https://developer.android.com/training/testing/other-components/ui-automator)\ntechnology from Google, but also functions only available through\n[ADB](https://developer.android.com/tools/adb), as well as functions only available\nvia the Android SDK inside a helper app). Tying it all together into a single, usable, WebDriver\ninterface is the incredibly useful (but incredibly challenging) art of driver development!","metadata":{"headerPath":"## Automation mapping","sectionCount":1,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/intro/drivers.md"}},{"pageContent":"## Multi-level architecture\n\nIn practice, this often results in a pretty complex architecture. Let's take iOS for example again.\nThe XCUITest framework (the one used by the Appium driver) expects code that calls it to be written\nin Objective-C or Swift. Furthermore, XCUITest code can only be run in a special mode triggered by\nXcode (and directly or indirectly, the Xcode command line tools). In other words, there's no\nstraightforward way to go from a Node.js function implementation (like `setUrl()` above) to\nXCUITest API calls.\n\nWhat the XCUITest driver authors have done is instead to split the driver into two parts: one part\nwritten in Node.js (the part which is incorporated into Appium and which initially handles the\nWebDriver commands), and the other part written in Objective-C (the part which actually gets run on\nan iOS device and makes XCUITest API calls). This makes interfacing with XCUITest possible, but\nintroduces the new problem of coordination between the two parts.\n\nThe driver authors could have chosen any of a number of very different strategies to model the\ncommunication between the Node.js side and the Objective-C side, but at the end of the day decided\nto use ... the WebDriver protocol! That's right, the Objective-C side of the XCUITest driver is\nitself a WebDriver implementation, called\n[WebDriverAgent](https://github.com/appium/webdriveragent).[^3]\n\n[^3]: You could in theory, therefore, point your WebDriver client straight to WebDriverAgent and\n bypass Appium entirely. This is usually not convenient, however, for a few reasons:\n\n - The Appium XCUITest driver builds and manages WebDriverAgent for you, which can be a pain and\n involves the use of Xcode.\n - The XCUITest driver does lots more than what can be done by WebDriverAgent, for example working\n with simulators or devices, installing apps, and the like.\n\nThe moral of the story is that driver architectures can become quite complicated and multilayered,\ndue to the nature of the problem we're trying to solve. It also means it can be difficult sometimes\nto tell where in this chain of technologies something has gone wrong, if you run into a problem\nwith a particular test. With the XCUITest world again, we have something like the following set of\ntechnologies all in play at the same time:","metadata":{"headerPath":"## Multi-level architecture","sectionCount":1,"recursiveSplit":true,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/intro/drivers.md"}},{"pageContent":"## Multi-level architecture\n\n- Your test code (in its programming language) - owned by you\n- The Appium client library - owned by Appium\n- The Selenium client library - owned by Selenium\n- The network (local or Internet)\n- The Appium server - owned by Appium\n- The Appium XCUITest driver - owned by Appium\n- WebDriverAgent - owned by Appium\n- Xcode - owned by Apple\n- XCUITest - owned by Apple\n- iOS itself - owned by Apple\n- macOS (where Xcode and iOS simulators run) - owned by Apple\n\nIt's a pretty deep stack!","metadata":{"headerPath":"## Multi-level architecture","sectionCount":1,"recursiveSplit":true,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/intro/drivers.md"}},{"pageContent":"## Proxy mode\n\nThere's one other important architectural aspect of drivers to understand. It can be exemplified\nagain by the XCUITest driver. Recall that we just discussed how the two \"halves\" of the XCUITest\ndriver both speak the WebDriver protocol---the Node.js half clicks right into Appium's WebDriver\nserver, and the Objective-c half (WebDriverAgent) is its own WebDriver implementation.\n\nThis opens up the possibility of Appium taking a shortcut in certain cases. Let's imagine that the\nXCUITest driver needs to implement the `Click Element` command. The internal code of this\nimplementation would look something like taking the appropriate parameters and constructing an HTTP\nrequest to the WebDriverAgent server. In this case, we're basically just reconstructing the\nclient's original call to the Appium server![^4] So there's really no need to even write a function\nimplementing the `Click Element` command. Instead, the XCUITest driver can just let Appium know\nthat this command should be proxied directly to some other WebDriver server.\n\n[^4]: It's not *exactly* the same call, because the Appium server and the WebDriverAgent server\n will generate different session IDs, but these differences will be handled transparently.\n\nIf you're not familiar with the concept of \"proxying,\" in this case it just means that the XCUITest\ndriver will not be involved at all in handling the command. Instead it will merely be repackaged\nand forwarded to WebDriverAgent at the protocol level, and WebDriverAgent's response will likewise\nbe passed back directly to the client, without any XCUITest driver code seeing it or modifying it.\n\nThis architectural pattern provides a nice bonus for driver authors who choose to deal with the\nWebDriver protocol everywhere, rather than constructing bespoke protocols. It also means that\nAppium can create wrapper drivers for any other existing WebDriver implementation very easily. If\nyou look at the [Appium Safari driver](https://github.com/appium/appium-safari-driver) code, for\nexample, you'll see that it implements basically no standard commands, because all of these are\nproxied directly to an underlying SafariDriver process.","metadata":{"headerPath":"## Proxy mode","sectionCount":1,"recursiveSplit":true,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/intro/drivers.md"}},{"pageContent":"## Proxy mode\n\nIt's important to understand that this proxying business is sometimes happening under the hood,\nbecause if you're ever diving into some open source driver code trying to figure out where\na command is implemented, you might be surprised to find no implementation at all in the Node.js\ndriver code itself! In that case, you'll need to figure out where commands are being proxied to so\nyou can look there for the appropriate implementation.\n\nOK, that's enough for this very detailed introduction to drivers!","metadata":{"headerPath":"## Proxy mode","sectionCount":1,"recursiveSplit":true,"filename":"drivers.md","relativePath":"appium/packages/appium/docs/en/intro/drivers.md"}},{"pageContent":"---\ntitle: Appium Project History\n---\n\nAppium has been around in one form or another since 2012. It's been under the\ndirection of various individuals and organizations, and it's even been\nimplemented in 3 different programming languages! Welcome to more than you ever\nwanted to know about how Appium got to be what is it today...\n\n## Early Inspiration\n\n[Dan Cuellar](https://twitter.com/thedancuellar) was the Test Manager at Zoosk\nin 2011, when he encountered a problem. The length of the test passes on the\niOS product was getting out of hand. Less testing was an option, but would come\nwith additional risk, especially with it taking several days to get patches\nthrough the iOS App Store Review process. He thought back to his days working\non websites and realized automation was the answer.\n\nDan surveyed the existing landscape of tools, only to find that all of them\nhand major drawbacks. The tool supplied by Apple, UIAutomation, required tests\nto be written in JavaScript, and did not allow for real-time debugging or\ninterpretation. It also had to be executed inside the Xcode profiling tool,\nInstruments. Other 3rd-party tools used private APIs and required SDKs and HTTP\nServers to be embedded into the application. This seemed highly undesirable.\n\nUnsatisfied with the existing options, Dan asked his manager for some\nadditional time to see if he could find a better way. He spent 2 weeks poking\nand prodding around to see if there was a way to use approved Apple\ntechnologies to automate an iOS application. The first implementation he tried\nused AppleScript to send messages to Mac UI elements using the OS\nX accessibility APIs. This worked to some degree, but would never work on real\ndevices, not to mention other drawbacks.\n\nSo he thought, what if I could get the UIAutomation framework to run in real\ntime like an interpreter? He looked into it and he determined that all he would\nneed to do is find a way to receive, execute, and reply to commands from within\na UIAutomation javascript program. Using the utility Apple provided for\nexecuting shell commands he was able to `cat` sequentially ordered text files\nto receive commands, `eval()` the output to execute them, and write them back\nto disk with `python`. He then prepared code in C# that implemented the\nSelenium-style syntax to write the sequentially ordered javascript commands.\niOSAuto is born.","metadata":{"headerPath":"","sectionCount":2,"filename":"history.md","relativePath":"appium/packages/appium/docs/en/intro/history.md"}},{"pageContent":"## Selenium Conference 2012\n\nDan was selected to speak at Selenium Conference 2012 in London about an\nentirely different topic. As part of his presentation, he showed off iOS\nAutomation using Selenium syntax to demonstrate writing platform-agnostic tests\nthat use separate platform-specific page objects with a common interface. To\nhis surprise, the cool test architecture would take a backseat to the spectacle\nof iOS tests running like WebDriver tests. Several people suggested that he\ngive a lightning talk later in the conference to explain exactly how it worked.\n\nOn the second day of the conference, Dan stepped up on stage to give the\nlightning talk. Jason Huggins, co-creator of Selenium, moderated the lightning\ntalks. Dan experienced technical difficulties getting his presentation to\nload, and Jason nearly had to move on to the next lightning talk. At the last\nmoment, the screen turned on and Dan jumped into his presentation. He explained\nthe details of his implementation and how it worked, begged for contributors,\nand in five minutes it was over. The crowd applauded politely, and he left the\nstage.\n\n## The Phone Rings\n\nFour months after the Selenium Conference, Jason called Dan. Jason had been\nworking on iOS testing support for a client at Sauce Labs. Jason remembered\nDan's lightning talk and thought the project might be useful to Jason's work,\nbut Dan's source code was not public. Jason asked Dan to meet up. Later that\nweek, Dan met Jason in a bar in San Francisco and showed him the source code\nfor iOS Auto.\n\nA long-time open source advocate, Jason encouraged Dan to release his code\nunder an open source license. In August, Dan [released the source\ncode](https://github.com/penguinho/appium-old/commit/3ab56d3a5601897b2790b5256351f9b5af3f9e90)\non GitHub in C#. Jason encouraged Dan to change the language to make the\nproject more appealing to potential contributors. Dan [uploaded a new version\nin\nPython](https://github.com/penguinho/appium-old/commit/9b891207be0957bf209a77242750da17d3eb8eda).\nIn September, Jason added a web server and [began to implement the WebDriver\nwire\nprotocol](https://github.com/hugs/appium-old/commit/ae8fe4578640d9af9137d0546190fa29317d1499)\nover HTTP, making iOS Auto scriptable from any Selenium WebDriver client\nlibrary in any language.","metadata":{"headerPath":"## Selenium Conference 2012","sectionCount":2,"filename":"history.md","relativePath":"appium/packages/appium/docs/en/intro/history.md"}},{"pageContent":"## The Mobile Testing Summit\n\nJason decided that the project should be presented at the [Mobile Testing\nSummit](https://twitter.com/mobtestsummit) in November, but suggested that the\nproject get a new name first. Many ideas were thrown out and they settled on\nAppleCart. A day later, while he was perusing some of Apple's guidance on\ncopyright and trademarks, Jason noticed that under the section of examples for\nnames Apple would defend its trademarks against, the first example was\n\"AppleCart\". He called Dan and informed him of the situation, and they\nbrainstormed for a bit before Jason hit the jackpot. Appium... Selenium for\nApps.\n\n## Sauce Labs and Node.js\n\nIn January 2013, not long after the Mobile Testing Summit, Sauce Labs decided\nto fully back Appium and provide more developer power. A task force was created\nto evaluate the current state and how best to move forward with the project.\nThe team, which included Jonathan Lipps (the current project lead), decided\nthat Appium needed a rebirth, and ultimately settled on Node.js as the\nframework to use. Node is well-known as a fast and efficient web server\nbackend, and at the end of the day, Appium is just a highly-specialized web\nserver. It was also decided that JavaScript as a language was accessible enough\nthat Appium would be able to grow into a larger community of open-source\ndevelopers with JavaScript than the other options on the table.\n\nIn just a few days, the team leveraged the existing work on Appium and had\na new version of Appium with as much functionality as the previous Python\nversion. The foundation had been laid for Appium's basic architecture, and we\nhave been successfully building on it since. A few weeks into this sprint,\nJonathan Lipps was formally designated project lead and he began to strategize\nhow to get more people from the community involved with Appium's development.","metadata":{"headerPath":"## The Mobile Testing Summit","sectionCount":2,"filename":"history.md","relativePath":"appium/packages/appium/docs/en/intro/history.md"}},{"pageContent":"## Appium Around the World\n\nUltimately, Jonathan decided that getting Appium in front of as many developers\nat conferences and meetups was the best way to attract users and contributions.\nAppium in its new incarnation was debuted at the [Google Test Automation\nConference 2013](https://www.youtube.com/watch?v=1J0aXDbjiUE). Later in 2013,\nAppium was presented at conferences and meetups all around the US, as well as\nin England, Poland, Portugal, and Australia. Notably, Jonathan had Appium\n[perform as instruments in a band](https://www.youtube.com/watch?v=zsbNVkayYRQ)\nand Dan Cuellar put together a fun [Appium video\nmontage](https://www.youtube.com/watch?v=xkzrEn0v0II) for Selenium Conference.\n\nBut during all these presentations and conferences, the project continued to\ndevelop. Early in 2013 we released Android and Selendroid support, making\nAppium the first truly cross-platform automation framework. The project also\ncontinued to attract users and contributors, and by the end of 2013, we'd\nalready had well over 1,000 commits.\n\n## The Road to Appium 1.0\n\nAppium began to grow and mature significantly. In May 2014,\nwe released Appium 1.0, which stood as a milestone in Appium's development.\nAppium was given\n[various](https://www.prnewswire.com/news-releases/black-duck-announces-black-duck-open-source-rookies-of-the-year-winners-242383341.html)\n[awards](https://www.infoworld.com/article/2241247/164642-bossie-awards-2014-the-best-open-source-application-development-tools.html)\nand became the most popular open-source cross-platform mobile automation\nframework. Stability improved, bugs were prioritized and fixed, and features\nadded. Sauce Labs increased the number of developers it donated to working\non Appium, but the entire community stayed involved in guiding the project and\ncontributing to it, and project governance continued to happen in the open, on\npublic mailing lists and GitHub's issue tracker.","metadata":{"headerPath":"## Appium Around the World","sectionCount":2,"filename":"history.md","relativePath":"appium/packages/appium/docs/en/intro/history.md"}},{"pageContent":"## The Appium Umbrella Broadens\n\nEventually, it became clear that the Appium codebase was not optimized for\na large team of distributed, sometime contributors. We took the opportunity as\na committer team to rewrite Appium from the ground up, using a more modern\nversion of the JavaScript language, and redoing Appium's architecture so that\nit was easy for users or third-party developers to build their own Appium\n\"drivers\". We wanted for it to be easier for new contributors to get ramped up\non the Appium codebase, and to see support for new platforms added to Appium by\ngroups other than the core team. That vision has begun to be fulfilled, with\ngroups like Microsoft and Youi.tv adding drivers to Appium for Windows desktop\napp automation and Youi.tv app automation, respectively.\n\n## Appium To The People\n\nIn late 2016, Sauce Labs donated Appium as a project to the [JS\nFoundation](https://js.foundation), in order to cement for the world Sauce's\ncommitment that Appium remains open source. The JS Foundation is a non-profit\nopen source stewardship organization which takes responsibility for holding the\ncopyright for open source projects, as well as ensuring they have a long and\nsuccessful tenure in the community. As a result of our move to a non-profit\nfoundation, we hope that the door will open even more widely for new\ncontributors, either as individuals or representing one of the many companies\nwhich now have an interest in seeing Appium move forward.\n\nEventually, the JS Foundation merged into the [OpenJS Foundation](https://openjsf.org),\nand Appium became an Impact Project in the foundation.\n\n## Appium 2.0\n\nAppium 2 was released in 2023 and introduced an entirely revamped architecture, shifting focus to Appium\nas an ecosystem rather than an all-in-one project. This unlocked the ability for anyone to develop\nand share their own Appium extensions (drivers and plugins), opening up a world of possibilities\nfor automation-related development for platforms far beyond iOS and Android! As a result,\nmany third-party extensions were created, such as new drivers for Flutter and Windows, plugins for\nmocking APIs and managing device farms, new Appium clients based on Rust and Swift, and much more.\n\nAround this time was also when we started a sponsorship program for Appium, which attracted various\nmajor and minor sponsors alike. This allowed us to give back to the Appium community, by compensating\ncontributors for their voluntary work on the project.","metadata":{"headerPath":"## The Appium Umbrella Broadens","sectionCount":3,"filename":"history.md","relativePath":"appium/packages/appium/docs/en/intro/history.md"}},{"pageContent":"## Appium 3.0\n\n2025 saw the release of Appium 3. This update was a lot smaller than Appium 2 and included only a\nfew behavioral changes, instead focusing on removing deprecated code and updating compatibility for\nmore modern ecosystems. Still, this reduced scope was also to be expected: since Appium 2, the\nmain feature development efforts had shifted to individual drivers and plugins, many of which had\ngone through multiple major updates during the Appium 2 era.","metadata":{"headerPath":"## Appium 3.0","sectionCount":1,"filename":"history.md","relativePath":"appium/packages/appium/docs/en/intro/history.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Appium in a Nutshell\n---\n\nAs mentioned on the main page, Appium aims to support UI automation of many _different platforms_\n(mobile, web, desktop, etc.). Not only that, but it also aims to support automation code written in\n_different languages_ (JS, Java, Python, etc.). Combining all of this functionality in a single\nprogram is a very daunting, if not impossible task!\n\nIn order to achieve this, Appium is effectively split into four parts:\n\n<div class=\"grid cards\" markdown>\n\n- :material-image-filter-center-focus-strong: __Appium Core__ - defines the core APIs\n- :material-car: __Drivers__ - implement connectivity to specific platforms\n- :octicons-code-16: __Clients__ - implement Appium's API in specific languages\n- :fontawesome-solid-plug: __Plugins__ - change or extend Appium's core functionality\n\n</div>\n\nTherefore, in order to start automating something with Appium, you need to:\n\n- Install Appium itself\n- Install a driver for your target platform\n- Install a client library for your target programming language\n- (Optional) install one or more plugins\n\nThese are the basics! If you are ready to jump in, proceed with the [Quickstart](../quickstart/index.md)!\n\nIf you wish to learn more details about how it all works, see these pages for background material:\n\n- [Appium Core](./appium.md)\n- [Appium Drivers](./drivers.md)\n- [Appium Clients](./clients.md)\n\nFinally, to learn about the origins of Appium, check out the [Appium Project History](./history.md).","metadata":{"headerPath":"","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/intro/index.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Getting Started\n---\n\nLet's get up and running with Appium! To successfully use this quickstart, it's recommended that\nyou first have read the [Introduction](../intro/index.md), so that you understand the concepts involved in\nrunning Appium and writing Appium scripts.\n\nThe basic plan for this quickstart is as follows:\n\n1. Install Appium\n1. Install an Appium driver and its dependencies\n - This guide provides instructions for the [UiAutomator2 driver](https://github.com/appium/appium-uiautomator2-driver)\n1. Install an Appium client library in your language of choice\n - This guide contains options for JavaScript, Python, Java, Ruby, and .NET\n1. Write and run a simple Appium automation script using a sample application\n\n### Requirements\n\nBefore getting started, make sure your system satisfies the\n[requirements](../quickstart/requirements.md) for running the Appium server. Additional requirements\nwill be discussed in conjunction with installing the UiAutomator2 driver. The guide also assumes\nyou have basic command line proficiency on your platform, for example being able to run commands, set\nand persist environment variables, etc...\n\nNow you're ready to get started! So head on over to [Installing Appium](./install.md).","metadata":{"headerPath":"","sectionCount":2,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/quickstart/index.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Install Appium\n---\n\n!!! info\n\n Before installing, make sure to check the [System Requirements](./requirements.md).\n\nAppium can be installed globally using `npm`:\n\n```bash\nnpm install -g appium\n```\n\n!!! note\n\n Other package managers are not currently supported.\n\n## Starting Appium\n\nAppium can be started [using the command line](../reference/cli/index.md):\n\n```\nappium\n```\n\nThis launches the Appium server process, which loads all the installed Appium drivers, and\nbegins waiting for new session requests from client connections (such as test automation scripts).\nSince the server process is independent from its clients, it must be explicitly launched before\nattempting to start a new session.\n\nWhen the server is launched, the console log will list all the valid URLs that clients can use to\nconnect to this server:\n\n```\n[Appium] You can provide the following URLs in your client code to connect to this server:\n[Appium] \thttp://127.0.0.1:4723/ (only accessible from the same host)\n(... any other URLs ...)\n```\n\nOnce a client requests a new session, the Appium server process will start logging all details about\nthis session until its termination. Keep this in mind - if you ever encounter issues with Appium\ntests, you can always check the server log for more details.\n\nSo what's next? Even though Appium is installed and running, it does not come bundled with any\ndrivers, which means it cannot automate anything yet. We will therefore set up automation for\nAndroid - continue to [Installing the UiAutomator2 Driver](./uiauto2-driver.md).","metadata":{"headerPath":"","sectionCount":2,"filename":"install.md","relativePath":"appium/packages/appium/docs/en/quickstart/install.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Next Steps\n---\n\nNow that you've successfully set up your system for Android automation and run a simple test,\nyou'll want to continue exploring this documentation. In particular, these are good guides and\nreference materials especially for beginners:\n\n- The [Ecosystem](../ecosystem/index.md) page: browse the available drivers, clients, plugins, and tools\n- [Managing Appium Drivers and Plugins](../guides/managing-exts.md)\n- [Capabilities](../guides/caps.md)\n- [Settings](../guides/settings.md)\n\nYou'll also find that the [Appium Inspector](https://github.com/appium/appium-inspector) is an\nindispensable tool for writing Appium tests, as it enables visual inspection of apps and\nhelps you to discover element locators for use in your test scripts.\n\nYou might also take advantage of one of the many online Appium courses available to you.\n\nGood luck and have fun!","metadata":{"headerPath":"","sectionCount":1,"filename":"next-steps.md","relativePath":"appium/packages/appium/docs/en/quickstart/next-steps.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: System Requirements\n---\n\nThe basic requirements for the Appium server are:\n\n* A macOS, Linux, or Windows operating system\n* [Node.js](https://nodejs.org) version in the [SemVer](https://semver.org) range `^20.19.0 || ^22.12.0 || >=24.0.0`\n * LTS is recommended\n* [`npm`](https://npmjs.com) version `>=10` (`npm` is usually bundled with Node.js, but can be upgraded\nindependently)\n\nBy itself, Appium is relatively lightweight and doesn't have significant disk space or RAM\nrequirements. It can even be run in resource-constrained environments like Raspberry Pi, so long as\nNode.js is available.\n\n### Driver Requirements\n\nDrivers for automating specific platforms will likely have other requirements. Refer to the\ndocumentation of the [Appium driver(s)](../ecosystem/drivers.md) for that platform for additional\ndependencies. It is almost universally the case that Appium drivers for a given platform will\nrequire the developer toolchain and SDKs for that platform to be installed.\n\nIn order to assist with driver requirements, each (official) driver comes with the Appium Doctor tool,\nwhich allows to verify if all requirements have been set up. Learn more about how to use this tool in\nthe [Command-Line Usage documentation](../reference/cli/extensions.md#doctor).","metadata":{"headerPath":"","sectionCount":2,"filename":"requirements.md","relativePath":"appium/packages/appium/docs/en/quickstart/requirements.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Write a Test (.NET)\n---\n\nThe [Appium .NET Client](https://github.com/appium/dotnet-client/) is\nan official Appium client in C#. This driver is an extension of the Selenium C# client. It has all the functionalities of the regular driver, but add Appium-specific methods on top of this. The driver is available on the public NuGet Gallery as [Appium.WebDriver](https://www.nuget.org/packages/Appium.WebDriver/).\n\nNow, we get inside the directory and create a new [NUnit](https://nunit.org/) project. We will also add the references to the Appium.Net driver, and other dependencies.\n\n```bash\ncd dotnet-client\ndotnet new nunit --name appiumtest\n\ncd appiumtest\n\n# This will install the latest 5.x version\ndotnet add package Appium.WebDriver --prerelease\ndotnet add package Newtonsoft.Json --version 13.0.3\n```\n\nOnce this is done, your project should have a placeholder file `UnitTest1.cs`. We will replace the code to include the OpenQA namespaces, an initialization of the driver, and the actual test.\n\n```C# title=\"UnitTest1.cs\"\nusing OpenQA.Selenium;\nusing OpenQA.Selenium.Appium;\nusing OpenQA.Selenium.Appium.Android;\nusing OpenQA.Selenium.Appium.Enums;\n\nnamespace appiumtest;\n\npublic class Tests\n{\n private AndroidDriver _driver;\n\n [OneTimeSetUp]\n public void SetUp()\n {\n var serverUri = new Uri(Environment.GetEnvironmentVariable(\"APPIUM_HOST\") ?? \"http://127.0.0.1:4723/\");\n var driverOptions = new AppiumOptions() {\n AutomationName = AutomationName.AndroidUIAutomator2,\n PlatformName = \"Android\",\n DeviceName = \"Android Emulator\",\n };\n\n driverOptions.AddAdditionalAppiumOption(\"appPackage\", \"com.android.settings\");\n driverOptions.AddAdditionalAppiumOption(\"appActivity\", \".Settings\");\n // NoReset assumes the app com.google.android is preinstalled on the emulator\n driverOptions.AddAdditionalAppiumOption(\"noReset\", true);\n\n _driver = new AndroidDriver(serverUri, driverOptions, TimeSpan.FromSeconds(180));\n _driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);\n }\n\n [OneTimeTearDown]\n public void TearDown()\n {\n _driver.Dispose();\n }\n\n [Test]\n public void TestFindApps()\n {\n _driver.StartActivity(\"com.android.settings\", \".Settings\");\n _driver.FindElement(By.XPath(\"//*[@text='Apps']\")).Click();\n }\n}\n```\n\n!!! note","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"test-dotnet.md","relativePath":"appium/packages/appium/docs/en/quickstart/test-dotnet.md"}},{"pageContent":"!!! note\n\n It's not within the scope of this guide to give a complete run-down on the dotnet client\n library or everything that's happening here, so we'll leave the code itself unexplained in\n detail for now. You may want to read up particularly on Appium\n [Capabilities](../guides/caps.md) in addition to familiarizing yourself with the\n [dotnet client driver documentation](https://github.com/appium/dotnet-client/) for a fuller explanation\n of the various API commands you see and what their purpose is.\n\nBasically, this code is doing the following:\n\n1. Defining a set of \"Capabilities\" (parameters) to send to the Appium server so Appium knows what\nkind of thing you want to automate. Some of these parameters can be overridden using environment variables.\n1. Starting an Appium session on the built-in Android settings app.\n1. Finding the \"Apps\" list item and clicking it.\n1. Ending the Appium session.\n\nThat's it! Let's give it a try. Before you run the test, make sure that you have an Appium server\nrunning in another terminal session, otherwise you'll get an error about not being able to connect\nto one. Then, you can execute the script:\n\n```bash\ndotnet test\n\n# Example output:\n# Starting test execution, please wait...\n# A total of 1 test files matched the specified pattern.\n\n# Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: 323 ms - appiumtest.dll (net7.0)\n```\n\nIf all goes well, you'll see the Settings app open up and navigate to the \"Apps\" view in the emulator before the app closes again.\n\nCongratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"test-dotnet.md","relativePath":"appium/packages/appium/docs/en/quickstart/test-dotnet.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Write a Test (Java)\n---\n\nThe Appium team maintains an official [client](https://github.com/appium/java-client) for the Java programming language.\nIt is built on top of [Selenium](https://github.com/SeleniumHQ/selenium).\nYou can also use this client in your Kotlin projects.\n\nFollow the [Add Appium java client to your test framework](https://github.com/appium/java-client#add-appium-java-client-to-your-test-framework)\ntutorial in order to connect the library to your test framework sources.\n\nThe Appium Java client has dedicated classes to support most of the official Appium drivers. For other drivers\nyou could simply use the [AppiumDriver](https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/AppiumDriver.java) class\nor build your custom derivatives from it. Check the [Drivers Support](https://github.com/appium/java-client#drivers-support)\narticle to learn more about the current driver class implementations.\n\nFollow the [Usage Examples](https://github.com/appium/java-client#usage-examples) article in order understand\nhow to invoke Java client features from your test framework.\n\nOnce you've managed to successfully run a test, you can read on for some [next steps](./next-steps.md) to explore.","metadata":{"headerPath":"","sectionCount":1,"filename":"test-java.md","relativePath":"appium/packages/appium/docs/en/quickstart/test-java.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Write a Test (JS)\n---\n\nTo write an Appium test in JavaScript (Node.js), we need to choose an Appium-compatible client\nlibrary. The best-maintained library and the one the Appium team recommends using is\n[WebdriverIO](https://webdriver.io), so let's use that. Since we already have Appium installed we\nknow our Node and NPM requirements are already satisfied. So just create a new project directory\nsomewhere on your computer and then initialize a new Node.js project in it:\n\n```bash\nnpm init\n```\n\nIt doesn't really matter what you put in the prompts, just so long as you end up with a valid\n`package.json`.\n\n\nNow, install the `webdriverio` package via NPM:\n\n```bash\nnpm i --save-dev webdriverio\n```\n\nOnce this is done, your `package.json` file should include a section like the following:\n\n```json title=\"package.json\"\n--8<-- \"./sample-code/quickstarts/js/package.json\"\n```\n\nNow it's time to type up the test itself. Create a new file called `test.js` with the following\ncontents:\n\n```js title=\"test.js\"\n--8<-- \"./sample-code/quickstarts/js/test.js\"\n```\n\n!!! note\n\n It's not within the scope of this guide to give a complete run-down on the WebdriverIO client\n library or everything that's happening here, so we'll leave the code itself unexplained in\n detail for now. You may want to read up particularly on Appium\n [Capabilities](../guides/caps.md) in addition to familiarizing yourself with the excellent\n [WebdriverIO documentation](https://webdriver.io/docs/gettingstarted) for a fuller explanation\n of the various API commands you see and what their purpose is.\n\n!!! note\n\n The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/js).\n\n\nBasically, this code is doing the following:\n\n1. Defining a set of \"Capabilities\" (parameters) to send to the Appium server so Appium knows what\nkind of thing you want to automate.\n1. Starting an Appium session on the built-in Android settings app.\n1. Finding the \"Apps\" list item and clicking it.\n1. Pausing for a moment purely for visual effect.\n1. Ending the Appium session.\n\nThat's it! Let's give it a try. Before you run the test, make sure that you have an Appium server\nrunning in another terminal session, otherwise you'll get an error about not being able to connect\nto one. Then, you can execute the script:\n\n```bash\nnode test.js\n```","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"test-js.md","relativePath":"appium/packages/appium/docs/en/quickstart/test-js.md"}},{"pageContent":"```bash\nnode test.js\n```\n\nIf all goes well, you'll see the Settings app open up and navigate to the \"Apps\" view before the\napp closes again.\n\nCongratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"test-js.md","relativePath":"appium/packages/appium/docs/en/quickstart/test-js.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Write a Test (Python)\n---\n\nThe [Appium Python Client](https://github.com/appium/python-client) is\nan official Appium client in Python, which is available via pypi under the [Appium-Python-Client](https://pypi.org/project/Appium-Python-Client/) package name.\nIt inherits from the [Selenium Python Binding](https://pypi.org/project/selenium/),\nso installing the Appium Python Client includes the selenium binding.\n\n```bash\npip install Appium-Python-Client\n```\n\nThis example uses Python's built-in `unittest` module, though you can use any Python test framework you want.\nThe Appium Python client adds the `appium:` vendor prefix automatically.\nYou usually do not need to worry about the prefix.\n\n```python title=\"test.py\"\n--8<-- \"./sample-code/quickstarts/py/test.py\"\n```\n\n!!! note\n\n It's not within the scope of this guide to give a complete run-down on the Python client\n library or everything that's happening here, so we'll leave the code itself unexplained in detail for now.\n\n - You may want to read up particularly on Appium [Capabilities](../guides/caps.md).\n - [functional test code](https://github.com/appium/python-client/tree/master/test/functional) in Python Client GitHub repository should help to find more working example.\n - [Documentation](https://appium.github.io/python-client-sphinx/) also helps to find methods\n defined in the Appium Python Client.\n\n!!! note\n\n The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/py).\n\n\nBasically, this code is doing the following:\n\n1. Defining a set of \"Capabilities\" (parameters) to send to the Appium server so Appium knows what\nkind of thing you want to automate.\n1. Starting an Appium session on the built-in Android settings app.\n1. Finding the \"Apps\" list item and clicking it.\n1. Pausing for a moment purely for visual effect.\n1. Ending the Appium session.\n\nThat's it! Let's give it a try. Before you run the test, make sure that you have an Appium server\nrunning in another terminal session, otherwise you'll get an error about not being able to connect\nto one. Then, you can execute the script:\n\n```bash\npython test.py\n```\n\nIf all goes well, you'll see the Settings app open up and navigate to the \"Apps\" view before the\napp closes again.\n\nCongratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.","metadata":{"headerPath":"","sectionCount":1,"filename":"test-py.md","relativePath":"appium/packages/appium/docs/en/quickstart/test-py.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Write a Test (Ruby)\n---\n\n\nThe [AppiumLib](https://github.com/appium/ruby_lib) and the [AppiumLibCore](https://github.com/appium/ruby_lib_core) (**recommended**) are official Appium client libraries in Ruby, which are available via gem under the [appium_lib](https://rubygems.org/gems/appium_lib) and the [appium_lib_core](https://rubygems.org/gems/appium_lib_core) package names. The appium_lib_core inherits from the Selenium Ruby Binding, and the appium_lib inherits from the appium_lib_core, so installing these libraries include the selenium binding. We recommend `appium_lib_core` if you need a less complex client-side solution. The `appium_lib` has some useful methods the core does not have, but for the cost of greater complexity and historical methods which may not work in the latest environment.\n\nAs the first step, let's initialize a Gemfile to manage the dependency:\n\n```bash\nbundle init\n```\n\nThen, you could add Appium Ruby Client dependency as below:\n\n```bash\nbundle add appium_lib_core\n# or\n# bundle add appium_lib\n```\n\nTest code example below uses `test-unit` module, thus please run:\n\n```bash\nbundle add test-unit\n```\n\nOnce these steps has done, your `Gemfile` file should include:\n\n```ruby title=\"Gemfile\"\n--8<-- \"./sample-code/quickstarts/rb/Gemfile\"\n```\n\nThe `appium_lib_core` is the main part as an Appium client.\n`appium_lib` has various helper methods, but the driver instance was ordinary designed to be used as a global variable. It could causes an issue to handle the instance.\n`appium_lib_core` does not have such a global variable.\n\nThis example is by the `appium_lib_core` with `test-unit` gem module.\nTes code in `appium_lib` should be similar.\n\n```ruby title=\"test.rb\"\n--8<-- \"./sample-code/quickstarts/rb/test.rb\"\n```\n\n!!! note\n\n It's not within the scope of this guide to give a complete run-down on the Ruby client\n library or everything that's happening here, so we'll leave the code itself unexplained in detail for now.\n\n - You may want to read up particularly on Appium [Capabilities](../guides/caps.md).\n - [functional test code](https://github.com/appium/ruby_lib_core/tree/master/test/functional) in the appium_lib_core GitHub repository should help to find more working example.\n - Documentation [appium_lib_core](https://www.rubydoc.info/github/appium/ruby_lib_core) and [appium_lib](https://www.rubydoc.info/github/appium/ruby_lib) also helps to find available methods.\n\n!!! note","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"test-rb.md","relativePath":"appium/packages/appium/docs/en/quickstart/test-rb.md"}},{"pageContent":"!!! note\n\n The sample code is available from [GitHub Appium repository](https://github.com/appium/appium/tree/master/packages/appium/sample-code/quickstarts/rb).\n\n\nBasically, this code is doing the following:\n\n1. Defining a set of \"Capabilities\" (parameters) to send to the Appium server so Appium knows what\nkind of thing you want to automate.\n1. Starting an Appium session on the built-in Android settings app.\n1. Finding the \"Apps\" list item and clicking it.\n1. Pausing for a moment purely for visual effect.\n1. Ending the Appium session.\n\nThat's it! Let's give it a try. Before you run the test, make sure that you have an Appium server\nrunning in another terminal session, otherwise you'll get an error about not being able to connect\nto one. Then, you can execute the script:\n\n```bash\n# Please run \"bundle install\" first if your environment has not run the installation command yet.\nbundle exec ruby test.rb\n```\n\nIf all goes well, you'll see the Settings app open up and navigate to the \"Apps\" view before the\napp closes again.\n\nCongratulations, you've started your Appium journey! Read on for some [next steps](./next-steps.md) to explore.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"test-rb.md","relativePath":"appium/packages/appium/docs/en/quickstart/test-rb.md"}},{"pageContent":"---\ntitle: Install the UiAutomator2 Driver\n---\n\nYou can't do much with Appium unless you have a [driver](../intro/drivers.md), which is an\ninterface that allows Appium to automate a particular platform.\n\n!!! info\n\n For this quickstart guide, we're going to be automating an app on the Android platform, because\n the system requirements for Android automation via Appium are the same as for Appium itself\n (whereas the iOS driver, for example, requires you to be using macOS).\n\nThe driver we're going to use is called the [UiAutomator2\nDriver](https://github.com/appium/appium-uiautomator2-driver). It's worth visiting that driver's\ndocumentation and bookmarking it, because it will be an invaluable reference down the line.\n\n## Set up Android automation requirements\n\nAccording to the driver, in addition to a working Appium server, we also need to set up the following:\n\n## Set up Android automation requirements > ### Android SDK\n\n- The easiest way to set up the Android SDK requirements is by downloading [Android Studio](https://developer.android.com/studio).\nWe need to use its SDK manager (_Settings -> Languages & Frameworks -> Android SDK_)\nto download the following items:\n - Android SDK Platform (select whichever Android platform we want to automate, for example, API level 30)\n - Android SDK Platform-Tools\n- If you wish, you can also download these items without Android Studio:\n - Android SDK Platform can be downloaded using `sdkmanager` included in [Android command-line tools](https://developer.android.com/studio#command-line-tools-only)\n - [Android SDK Platform-Tools](https://developer.android.com/tools/releases/platform-tools)\n- Set up the `ANDROID_HOME` environment variable to point to the directory where the Android SDK is\ninstalled. You can usually find the path to this directory in the Android Studio SDK manager. It\nwill contain the `platform-tools` and other directories.\n\n## Set up Android automation requirements > ### Java JDK\n\n- Install the Java JDK (for the most recent Android API levels, JDK 9 is required, otherwise JDK\n8 is required). You can download this from [Oracle](https://jdk.java.net/) or [Adoptium](https://adoptium.net/en-GB/temurin/releases/).\nMake sure you get the JDK and not the JRE.\n- Set up the `JAVA_HOME` environment variable to point to the JDK home directory. It will contain\nthe `bin`, `include`, and other directories.","metadata":{"headerPath":"","sectionCount":4,"filename":"uiauto2-driver.md","relativePath":"appium/packages/appium/docs/en/quickstart/uiauto2-driver.md"}},{"pageContent":"## Set up Android automation requirements > ### Prepare the Device\n\n- If using an emulator, use Android Studio to create and launch an Android Virtual Device (AVD).\nYou may need to download the system images for the API level of the emulator you want to\ncreate. Using the AVD creation wizard in Android Studio is generally the easiest way to do all of\nthis.\n- If using a real device, you should [set it up for development and enable USB Debugging](https://developer.android.com/studio/debug/dev-options).\n- With the emulator or device connected, you can run `adb devices` (via the binary located at\n`$ANDROID_HOME/platform-tools/adb`) to verify that your device shows up as connected.\n\nOnce your device shows up as connected in `adb`, and you've verified that the environment variables\nare set up correctly, you should be good to go! If you ran into problems with any of these steps,\nrefer to the driver documentation, or the various Android or Java documentation sites as necessary.\n\nAlso, congratulations: whether or not you intended to, you now have the Android developer toolchain\nset up on your system, so you can get busy making Android apps if you want!\n\n## Install the driver itself","metadata":{"headerPath":"## Set up Android automation requirements > ### Prepare the Device","sectionCount":2,"filename":"uiauto2-driver.md","relativePath":"appium/packages/appium/docs/en/quickstart/uiauto2-driver.md"}},{"pageContent":"## Install the driver itself > ### Standard Install\n\nLike all Appium drivers, the UiAutomator2 driver is installed via the [Appium Extension CLI](../reference/cli/extensions.md).\nSince UiAutomator2 is maintained by the core Appium team, it has an 'official' driver name\n(`uiautomator2`), which makes the installation simpler.\n\nBefore installing, make sure your Appium server is _not_ running (if it is, quit it with _Ctrl-C_).\nThen run the following command:\n\n```bash\nappium driver install uiautomator2\n```\n\nIt should produce output that looks something like:\n\n```\nAttempting to find and install driver 'uiautomator2'\n✔ Installing 'uiautomator2' using NPM install spec 'appium-uiautomator2-driver'\nDriver uiautomator2@2.0.5 successfully installed\n- automationName: UiAutomator2\n- platformNames: [\"Android\"]\n```\n\nNote how the installation process specifies what platforms is the driver valid for (in this case,\n`Android`), and what automation name (the `appium:automationName` [capability](../guides/caps.md))\nmust be used to select this driver for use during an Appium session (in this case, `UiAutomator2`).\n\n!!! note\n\n In this quickstart we have used the [Extension CLI](../reference/cli/extensions.md) to install the\n UiAutomator2 driver, but if you are incorporating Appium into a Node.js project, you might\n prefer to use `npm` to manage Appium and its connected drivers. To learn more about this\n technique, visit the guide on [managing Appium extensions](../guides/managing-exts.md).\n\n## Install the driver itself > ### Batch Install\n\nYou may want to use Appium with more than one driver. One way to accomplish this is to run\n`appium driver install <driver-name>` for each individual driver, but you can also install multiple\ndrivers in one go:\n\n```\nappium setup\n```\n\nRunning this will install Appium's mobile-specific drivers: UiAutomator2, [XCUITest](https://appium.github.io/appium-xcuitest-driver/)\n(only if running macOS), and [Espresso](https://github.com/appium/appium-espresso-driver).\n\nYou can also use this command to batch install drivers for desktop applications or desktop browsers.\nFor more details on this, refer to the [Setup command documentation](../reference/cli/setup.md).","metadata":{"headerPath":"## Install the driver itself > ### Standard Install","sectionCount":2,"filename":"uiauto2-driver.md","relativePath":"appium/packages/appium/docs/en/quickstart/uiauto2-driver.md"}},{"pageContent":"## Install the driver itself > ### Validating the Install\n\nThe UiAutomator2 driver, like all official Appium drivers, comes with the Appium Doctor tool, which\nallows validating whether all prerequisites have been set up correctly:\n\n```\nappium driver doctor uiautomator2\n```\n\nThis guide has focused on essential requirements, so Appium Doctor may suggest one or more optional\nfixes. But if you see `0 required fixes needed`, that means everything is set up!\n\nNow, start the Appium server again (run `appium`), and you should see that the newly-installed\ndriver is listed as available:\n\n```\n[Appium] Available drivers:\n[Appium] - uiautomator2@2.0.5 (automationName 'UiAutomator2')\n```\n\nWith the Android setup complete and the UiAutomator2 driver installed, you're ready to write your\nfirst test! Now select your preferred language and give it a shot:\n\n<div class=\"grid cards\" markdown>\n\n- :material-language-javascript: [__JavaScript__](./test-js.md)\n- :material-language-java: [__Java__](./test-java.md)\n- :material-language-python: [__Python__](./test-py.md)\n- :material-language-ruby: [__Ruby__](./test-rb.md)\n- :material-dot-net: [__.NET C#__](./test-dotnet.md)\n\n</div>","metadata":{"headerPath":"## Install the driver itself > ### Validating the Install","sectionCount":1,"filename":"uiauto2-driver.md","relativePath":"appium/packages/appium/docs/en/quickstart/uiauto2-driver.md"}},{"pageContent":"---\ntitle: Appium Protocol\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav {\n display: none;\n }\n</style>\n\nThe following is a list of endpoints supported in Appium, that are defined in the Appium extension\nof the W3C WebDriver protocol.\n\n### getAppiumSessions\n\n```\nGET /appium/sessions\n```\n\nRetrieves information about all active server sessions.\n\n!!! info\n\n The `session_discovery` [insecure feature](../../guides/security.md) must be enabled to use this endpoint.\n\n### getAppiumSessions > #### Response\n\n`TimestampedMultiSessionData[]` - an array of session data objects. Each object has the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`capabilities`|Session capabilities|object|\n|`created`|Session creation time (in milliseconds) as a Unix timestamp|number|\n|`id`|Session ID|string|\n\n### getAppiumSessionCapabilities\n\n```\nGET /session/:sessionId/appium/capabilities\n```\n\nRetrieves the [session capabilities](../../guides/caps.md).\n\n### getAppiumSessionCapabilities > #### Response\n\n`SessionCapabilities` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`capabilities`|Session capabilities|object|\n\n### getSettings\n\n```\nGET /session/:sessionId/appium/settings\n```\n\nRetrieves the [current session settings](../../guides/settings.md).\n\n### getSettings > #### Response\n\n`Settings` - an object containing setting names and their values\n\n### updateSettings\n\n```\nPOST /session/:sessionId/appium/settings\n```\n\nUpdates the specified session settings. Any other previously set settings will remain unchanged.\n\n### updateSettings > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`settings`|Object containing the names and values of the settings to be updated|object|\n\n### updateSettings > #### Response\n\n`null`\n\n### listCommands\n\n```\nGET /session/:sessionId/appium/commands\n```\n\nRetrieves the URL endpoints and WebDriver BiDi commands supported in the current session.\n\n### listCommands > #### Response\n\n`ListCommandsResponse` - an object containing all supported endpoints and BiDi commands, grouped by\ntheir origin (base Appium, driver-specific, or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command.ts)\nfor a detailed structure of this object.\n\n### listExtensions\n\n```\nGET /session/:sessionId/appium/extensions\n```\n\nRetrieves the [execute methods](../../guides/execute-methods.md) supported in the current session.","metadata":{"headerPath":"","sectionCount":13,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/reference/api/appium.md"}},{"pageContent":"### listExtensions > #### Response\n\n`ListExtensionsResponse` - an object containing all supported execute methods, grouped by their\norigin (driver-specific or plugin-specific). Refer to [the type definition file](https://github.com/appium/appium/blob/master/packages/types/lib/command.ts)\nfor a detailed structure of this object.\n\n### getLogEvents\n\n```\nPOST /session/:sessionId/appium/events\n```\n\nRetrieves events that have occurred in the current session. By default, only driver command\nexecutions are recorded in the log, but drivers or plugins may define additional event types.\nClients can log events by using the [`logCustomEvent`](#logcustomevent) endpoint.\n\n### getLogEvents > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`type?`|One or more types to filter the returned events|string or array<string>|\n\n### getLogEvents > #### Response\n\n`EventHistory` - an object whose keys correspond to the types of logged events. Event types can be\ngrouped into three categories, as shown by the following example response:\n\n```json\n{\n \"commands\": [\n { \"cmd\": \"getStatus\", \"startTime\": 1756887645447, \"endTime\": 1756887645454 }\n ],\n \"driverevent\": [1756887645454],\n \"namespace:event\": [1756887645454]\n}\n```\n\n* The `commands` key is always included in the endpoint response. Its value is an array of objects,\n where each object includes 3 parameters:\n * `cmd`: name of the executed command\n * `startTime`: the command execution start time (in milliseconds), as a Unix timestamp\n * `endTime`: the command execution end time (in milliseconds), as a Unix timestamp\n* Other non-namespaced keys are specific to driver/plugin implementations. Their value is an array\n of event times (in milliseconds), as Unix timestamps.\n* Namespaced keys can be added using the `logCustomEvent` endpoint, but may also be provided by\n drivers/plugins. Their value is an array of event times (in milliseconds), as Unix timestamps.\n\n### logCustomEvent\n\n```\nPOST /session/:sessionId/appium/log_event\n```\n\nLogs a custom event, which can be retrieved using the [`getLogEvents`](#getlogevents) endpoint.\n\n### logCustomEvent > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`vendor`|Name of the namespace (vendor) used to prefix the event|string|\n|`event`|Name of the event|string|\n\n### logCustomEvent > #### Response\n\n`null`\n\n### getDeviceTime\n\n```\nPOST /session/:sessionId/appium/device/system_time\n```\n\nRetrieves the current system time of the device under test.","metadata":{"headerPath":"### listExtensions > #### Response","sectionCount":8,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/reference/api/appium.md"}},{"pageContent":"### getDeviceTime > #### Parameters\n\n|Name|Description|Type|Default|\n|--|--|--|--|\n|`format?`|Format to use for the returned timestamp|string|`YYYY-MM-DDTHH:mm:ssZ`|\n\n### getDeviceTime > #### Response\n\n`string` - the device time\n\n### activateApp\n\n```\nPOST /session/:sessionId/appium/device/activate_app\n```\n\nActivates an app on the device under test.\n\n### activateApp > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`appId` or `bundleId`|App identifier such as Android app package or iOS bundle ID|string|\n|`options?`|Driver-specific launch options|unknown|\n\n### activateApp > #### Response\n\n`void`\n\n### terminateApp\n\n```\nPOST /session/:sessionId/appium/device/terminate_app\n```\n\nTerminates an app on the device under test.\n\n### terminateApp > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`appId` or `bundleId`|App identifier such as Android app package or iOS bundle ID|string|\n|`options?`|Driver-specific termination options|unknown|\n\n### terminateApp > #### Response\n\n`void`\n\n### queryAppState\n\n```\nPOST /session/:sessionId/appium/device/app_state\n```\n\nRetrieves the state of an app on the device under test.\n\n### queryAppState > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`appId` or `bundleId`|App identifier such as Android app package or iOS bundle ID|string|\n\n### queryAppState > #### Response\n\n`number` - an integer value indicating the app state:\n\n|Number|App State|\n|--|--|\n|`0`|Not installed|\n|`1`|Not running|\n|`2`|Running in background suspended|\n|`3`|Running in background|\n|`4`|Running in foreground|\n\n### installApp\n\n```\nPOST /session/:sessionId/appium/device/install_app\n```\n\nInstalls an app on the device under test.\n\n### installApp > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`appPath`|Absolute local filepath or URL to an app file|string|\n|`options?`|Driver-specific install options|unknown|\n\n### installApp > #### Response\n\n`void`\n\n### removeApp\n\n```\nPOST /session/:sessionId/appium/device/remove_app\n```\n\nUninstalls an app from the device under test.\n\n### removeApp > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`appId` or `bundleId`|App identifier such as Android app package or iOS bundle ID|string|\n|`options?`|Driver-specific uninstall options|unknown|\n\n### removeApp > #### Response\n\n`boolean` - `true` if uninstall was successful, otherwise `false`\n\n### isAppInstalled\n\n```\nPOST /session/:sessionId/appium/device/app_installed\n```\n\nDetermines if an app is installed on the device under test.","metadata":{"headerPath":"### getDeviceTime > #### Parameters","sectionCount":18,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/reference/api/appium.md"}},{"pageContent":"### isAppInstalled > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`appId` or `bundleId`|App identifier such as Android app package or iOS bundle ID|string|\n\n### isAppInstalled > #### Response\n\n`boolean` - `true` if app is installed, otherwise `false`\n\n### hideKeyboard\n\n```\nPOST /session/:sessionId/appium/device/hide_keyboard\n```\n\nAttempts to hide the virtual keyboard on the device under test.\n\n### hideKeyboard > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`key?`|Text of a key to use to hide the keyboard|string|\n|`keyCode?`|Key code to trigger to hide the keyboard|string|\n|`keyName?`|Name of a key to use to hide the keyboard|string|\n|`strategy?`|Driver-specific name of a hiding strategy to follow|string|\n\n### hideKeyboard > #### Response\n\n`boolean` - `true` if the operation was successful, otherwise `false`. Note that some platforms\nmay never return a `false` value.\n\n### isKeyboardShown\n\n```\nGET /session/:sessionId/appium/device/is_keyboard_shown\n```\n\nDetermines if the virtual keyboard is shown on the device under test.\n\n### isKeyboardShown > #### Response\n\n`boolean` - `true` if the keyboard is shown, otherwise `false`\n\n### pushFile\n\n```\nPOST /session/:sessionId/appium/device/push_file\n```\n\nPushes data to a file on the device under test.\n\n### pushFile > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`data`|Base64-encoded data to be written to the file|string|\n|`path`|Remote path on the device to create the file at|string|\n\n### pushFile > #### Response\n\n`void`\n\n### pullFile\n\n```\nPOST /session/:sessionId/appium/device/pull_file\n```\n\nRetrieves data from a file on the device under test.\n\n### pullFile > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`path`|Remote path of the file on the device|string|\n\n### pullFile > #### Response\n\n`string` - the Base64-encoded contents of the file\n\n### pullFolder\n\n```\nPOST /session/:sessionId/appium/device/pull_folder\n```\n\nRetrieves data from a directory on the device under test.\n\n### pullFolder > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`path`|Remote path of the directory on the device|string|\n\n### pullFolder > #### Response\n\n`string` - the Base64-encoded zip file of the directory contents","metadata":{"headerPath":"### isAppInstalled > #### Parameters","sectionCount":16,"filename":"appium.md","relativePath":"appium/packages/appium/docs/en/reference/api/appium.md"}},{"pageContent":"---\ntitle: WebDriver BiDi Protocol\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav {\n display: none;\n }\n</style>\n\nThe following is a list of [W3C WebDriver BiDi protocol](https://w3c.github.io/webdriver-bidi/)\ncommands supported in Appium.\n\nUnlike other protocols that specify URL endpoints, the WebDriver BiDi protocol specifies commands\nsent as a websocket event, that both drivers and clients can emit or listen to.\n\n### bidiStatus\n\n```\nsession.status\n```\n\n> WebDriver BiDi documentation: [session.status](https://w3c.github.io/webdriver-bidi/#command-session-status)\n\nRetrieves the current status of the Appium server.\n\n### bidiStatus > #### Response\n\n[`GetStatusResult`](./webdriver.md#response_2)\n\n### bidiSubscribe\n\n```\nsession.subscribe\n```\n\n> WebDriver BiDi documentation: [session.subscribe](https://w3c.github.io/webdriver-bidi/#command-session-subscribe)\n\nSubscribes to one or more BiDi events.\n\n### bidiSubscribe > #### Parameters\n\n|Name|Description|Type|Default|\n|--|--|--|--|\n|`contexts?`|Contexts in which to subscribe to the specified events. By default, the global context scope is applied.|string[]|`['']`|\n|`events`|Names of events to subscribe to|string[]||\n\n### bidiSubscribe > #### Response\n\n`null`\n\n### bidiUnsubscribe\n\n```\nsession.unsubscribe\n```\n\n> WebDriver BiDi documentation: [session.unsubscribe](https://w3c.github.io/webdriver-bidi/#command-session-unsubscribe)\n\nUnsubscribes from one or more BiDi events.\n\n### bidiUnsubscribe > #### Parameters\n\n|Name|Description|Type|Default|\n|--|--|--|--|\n|`contexts?`|Contexts in which to unsubscribe from the specified events. By default, the global scope is applied.|string[]|`['']`|\n|`events`|Names of events to unsubscribe from|string[]||\n\n### bidiUnsubscribe > #### Response\n\n`null`","metadata":{"headerPath":"","sectionCount":9,"filename":"bidi.md","relativePath":"appium/packages/appium/docs/en/reference/api/bidi.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: API Endpoints\n---\n\nHere you can find various API endpoints exposed by the main Appium module through its base driver,\nas well as the endpoints added or modified by official plugins.\n\nSince all Appium drivers inherit the Appium base driver, they support all of its endpoints as well,\nbut may additionally define endpoints of their own. Refer to the documentation of your\n[Appium driver](../../ecosystem/drivers.md) to learn about its specific endpoints.\n\nThe recommended way of calling these API endpoints is through your [Appium client](../../ecosystem/clients.md).\nRefer to the documentation of your client for the exact commands used to invoke specific endpoints.\n\nAll endpoints are grouped by their protocol, with an additional group for plugin endpoints:\n\n<div class=\"grid cards\" markdown>\n\n- [__WebDriver Protocol__](./webdriver.md)\n- [__WebDriver BiDi Protocol__](./bidi.md)\n- [__JSON Wire Protocol__](./jsonwp.md)\n- [__Mobile JSON Wire Protocol__](./mjsonwp.md)\n- [__Appium Protocol__](./appium.md)\n- [__Other Protocols__](./others.md)\n- [__Endpoints Used by Official Plugins__](./plugins.md)\n\n</div>","metadata":{"headerPath":"","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/reference/api/index.md"}},{"pageContent":"---\ntitle: JSON Wire Protocol\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav {\n display: none;\n }\n</style>\n\nThe following is a list of legacy [JSON Wire Protocol (JSONWP)](https://www.selenium.dev/documentation/legacy/json_wire_protocol/)\nendpoints supported in Appium.\n\n### getSession\n\n```\nGET /session/:sessionId\n```\n\n> JSONWP documentation: [/session/:sessionId](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionid)\n\nRetrieves the capabilities of the current session.\n\nAppium implements a modified version of this endpoint. If the `appium:eventTimings` capability is\nset to `true`, the returned result will additionally include the `events` key, whose value contains\nthe event history and timings.\n\n!!! warning \"Deprecated\"\n\n For retrieving capabilities, please use [`getAppiumSessionCapabilities`](./appium.md#getappiumsessioncapabilities).<br />\n For retrieving event history, please use [`getLogEvents`](./appium.md#getlogevents).\n\n### getSession > #### Response\n\n`Capabilities` - an object containing the session capabilities, and the event history (if applicable)\n\n### availableIMEEngines\n\n```\nGET /session/:sessionId/ime/available_engines\n```\n\n> JSONWP documentation: [/session/:sessionId/ime/available_engines](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimeavailable_engines)\n\nRetrieves all IME (input method editor) engines available on the device under test.\n\n!!! warning \"Deprecated\"\n\n In the future, this endpoint will be moved to the [UiAutomator2 and Espresso drivers](../../ecosystem/drivers.md)\n\n### availableIMEEngines > #### Response\n\n`string[]` - a list of available IME engines\n\n### getActiveIMEEngine\n\n```\nGET /session/:sessionId/ime/active_engine\n```\n\n> JSONWP documentation: [/session/:sessionId/ime/active_engine](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimeactive_engine)\n\nRetrieves the name of the active IME engine.\n\n!!! warning \"Deprecated\"\n\n In the future, this endpoint will be moved to the UiAutomator2 and Espresso drivers\n\n### getActiveIMEEngine > #### Response\n\n`string` - the name of the active IME engine","metadata":{"headerPath":"","sectionCount":7,"filename":"jsonwp.md","relativePath":"appium/packages/appium/docs/en/reference/api/jsonwp.md"}},{"pageContent":"### isIMEActivated\n\n```\nGET /session/:sessionId/ime/activated\n```\n\n> JSONWP documentation: [/session/:sessionId/ime/activated](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimeactivated)\n\nDetermines if IME input is available and active.\n\n!!! warning \"Deprecated\"\n\n In the future, this endpoint will be moved to the UiAutomator2 and Espresso drivers\n\n### isIMEActivated > #### Response\n\n`boolean` - `true` if IME is active, otherwise `false`\n\n### deactivateIMEEngine\n\n```\nPOST /session/:sessionId/ime/deactivate\n```\n\n> JSONWP documentation: [/session/:sessionId/ime/deactivate](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimedeactivate)\n\nDeactivates the currently active IME engine.\n\n!!! warning \"Deprecated\"\n\n In the future, this endpoint will be moved to the UiAutomator2 and Espresso drivers\n\n### deactivateIMEEngine > #### Response\n\n`null`\n\n### activateIMEEngine\n\n```\nPOST /session/:sessionId/ime/activate\n```\n\n> JSONWP documentation: [/session/:sessionId/ime/activate](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidimeactivate)\n\nActivates an IME engine.\n\n!!! warning \"Deprecated\"\n\n In the future, this endpoint will be moved to the UiAutomator2 and Espresso drivers\n\n### activateIMEEngine > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`engine`|Name of the IME engine to activate|string|\n\n### activateIMEEngine > #### Response\n\n`null`\n\n### getOrientation\n\n```\nGET /session/:sessionId/orientation\n```\n\n> JSONWP documentation: [/session/:sessionId/orientation](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidorientation)\n\nRetrieves the current orientation of the device under test.\n\n### getOrientation > #### Response\n\n`string` - either `PORTRAIT` or `LANDSCAPE`\n\n### setOrientation\n\n```\nPOST /session/:sessionId/orientation\n```\n\n> JSONWP documentation: [/session/:sessionId/orientation](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidorientation)\n\nSets the orientation of the device under test.\n\n### setOrientation > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`orientation`|New device orientation. Supported values are `PORTRAIT` or `LANDSCAPE`.|string|\n\n### setOrientation > #### Response\n\n`null`","metadata":{"headerPath":"### isIMEActivated","sectionCount":12,"filename":"jsonwp.md","relativePath":"appium/packages/appium/docs/en/reference/api/jsonwp.md"}},{"pageContent":"### getGeoLocation\n\n```\nGET /session/:sessionId/location\n```\n\n> JSONWP documentation: [/session/:sessionId/location](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidlocation)\n\nRetrieves the current location of the device under test.\n\n!!! warning \"Deprecated\"\n\n Please use driver-specific extension methods such as `mobile: getGeoLocation` or\n `mobile: getSimulatedLocation`\n\n### getGeoLocation > #### Response\n\n`Location` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`altitude`|Altitude of the device location|number|\n|`latitude`|Latitude of the device location|number|\n|`longitude`|Longitude of the device location|number|\n\n### setGeoLocation\n\n```\nPOST /session/:sessionId/location\n```\n\n> JSONWP documentation: [/session/:sessionId/location](https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidlocation)\n\nSets the current location of the device under test.\n\n!!! warning \"Deprecated\"\n\n Please use driver-specific extension methods such as `mobile: setGeoLocation` or\n `mobile: setSimulatedLocation`\n\n### setGeoLocation > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`location`|New device latitude, longitude and altitude|[`Location`](#response_6)|\n\n### setGeoLocation > #### Response\n\n`null`","metadata":{"headerPath":"### getGeoLocation","sectionCount":5,"filename":"jsonwp.md","relativePath":"appium/packages/appium/docs/en/reference/api/jsonwp.md"}},{"pageContent":"---\ntitle: Mobile JSON Wire Protocol\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav {\n display: none;\n }\n</style>\n\nThe following is a list of legacy [Mobile JSON Wire Protocol (MJSONWP)](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)\nendpoints supported in Appium.\n\n### getRotation\n\n```\nGET /session/:sessionId/rotation\n```\n\n> MJSONWP documentation: [Device Rotation](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#device-rotation)\n\nRetrieves the current spatial orientation of the device under test.\n\n### getRotation > #### Response\n\n`Rotation` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`x`|Degrees by which the device is rotated on its X axis|number|\n|`y`|Degrees by which the device is rotated on its Y axis|number|\n|`z`|Degrees by which the device is rotated on its Z axis|number|\n\n### setRotation\n\n```\nPOST /session/:sessionId/rotation\n```\n\n> MJSONWP documentation: [Device Rotation](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#device-rotation)\n\nSets the spatial orientation of the device under test.\n\n### setRotation > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`x`|Degrees by which the device is rotated on its X axis|number|\n|`y`|Degrees by which the device is rotated on its Y axis|number|\n|`z`|Degrees by which the device is rotated on its Z axis|number|\n\n### setRotation > #### Response\n\n`null`\n\n### getCurrentContext\n\n```\nGET /session/:sessionId/context\n```\n\n> MJSONWP documentation: [Webviews and Other Contexts](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#webviews-and-other-contexts)\n\nRetrieves the active application context.\n\n### getCurrentContext > #### Response\n\n`string` - the name of the active context\n\n### setContext\n\n```\nPOST /session/:sessionId/context\n```\n\n> MJSONWP documentation: [Webviews and Other Contexts](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#webviews-and-other-contexts)\n\nSets an application context as the active context.\n\n### setContext > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`name`|Name of the context to set as the active one|string|\n\n### setContext > #### Response\n\n`null`\n\n### getContexts\n\n```\nGET /session/:sessionId/contexts\n```\n\n> MJSONWP documentation: [Webviews and Other Contexts](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#webviews-and-other-contexts)\n\nRetrieves all available application contexts.","metadata":{"headerPath":"","sectionCount":12,"filename":"mjsonwp.md","relativePath":"appium/packages/appium/docs/en/reference/api/mjsonwp.md"}},{"pageContent":"### getContexts > #### Response\n\n`string[]` - the names of available contexts\n\n### getNetworkConnection\n\n```\nGET /session/:sessionId/network_connection\n```\n\n> MJSONWP documentation: [Device Modes](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#device-modes)\n\nRetrieves the current state of network types (data, Wi-Fi, airplane mode).\n\n!!! warning \"Deprecated\"\n\n Please use driver-specific extension methods such as `mobile: getConnectivity`\n\n### getNetworkConnection > #### Response\n\n`NetworkConnectionState` - a number indicating the current network state:\n\n|Value|Data|Wi-Fi|Airplane Mode|\n|--|--|--|--|\n|`0`|OFF|OFF|OFF|\n|`1`|OFF|OFF|ON|\n|`2`|OFF|ON|OFF|\n|`4`|ON|OFF|OFF|\n|`6`|ON|ON|OFF|\n\n### setNetworkConnection\n\n```\nPOST /session/:sessionId/network_connection\n```\n\n> MJSONWP documentation: [Device Modes](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#device-modes)\n\nSets the state of network types (data, Wi-Fi, airplane mode).\n\n!!! warning \"Deprecated\"\n\n Please use driver-specific extension methods such as `mobile: setConnectivity`\n\n### setNetworkConnection > #### Parameters\n\n|<div style=\"width:6em\">Name</div>|Description|<div style=\"width:18em\">Type</div>|\n|--|--|--|\n|`parameters`|Object containing the `type` key, whose value is the desired network state|`{\"type\": `[`NetworkConnectionState`](#response_5)`}`|\n\n### setNetworkConnection > #### Response\n\n[`NetworkConnectionState`](#response_5) - the new network state","metadata":{"headerPath":"### getContexts > #### Response","sectionCount":6,"filename":"mjsonwp.md","relativePath":"appium/packages/appium/docs/en/reference/api/mjsonwp.md"}},{"pageContent":"---\ntitle: Other Protocols\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav .md-nav {\n display: none;\n }\n</style>\n\nThe following is a list of endpoints supported in Appium that are defined in other protocols.\n\n## Chromedriver Protocol\n\nThe Chromedriver protocol is an extension of the W3C WebDriver protocol, supported in Appium\nclients using Chromedriver. It specifies both its own extension commands, as well as\nvendor-agnostic commands.\n\n!!! warning\n\n Endpoints specified by this protocol are not officially documented.\n\n## Chromedriver Protocol > ### executeCdp\n\n```\nPOST /session/:sessionId/:vendor/cdp/execute\n```\n\nExecutes a Chrome DevTools Protocol (CDP) method, using the implementation of the vendor identified\nby `:vendor`. Refer to [the CDP documentation](https://chromedevtools.github.io/devtools-protocol/)\nfor a list of available methods and their parameters.\n\n## Chromedriver Protocol > ### executeCdp > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`cmd`|Name of the CDP method to execute|string|\n|`params`|Parameters passed to the CDP method|object|\n\n## Chromedriver Protocol > ### executeCdp > #### Response\n\n`any` - the result of executing the CDP method\n\n## Compute Pressure Protocol\n\nThe [Compute Pressure protocol](https://www.w3.org/TR/compute-pressure/) is an extension of the W3C\nWebDriver protocol.\n\n## Compute Pressure Protocol > ### createVirtualPressureSource\n\n```\nPOST /session/:sessionId/pressuresource\n```\n\n> Compute Pressure documentation: [Create Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#create-virtual-pressure-source)\n\nCreates a new virtual pressure source.\n\n## Compute Pressure Protocol > ### createVirtualPressureSource > #### Parameters\n\n|<div style=\"width:6em\">Name</div>|Description|Type|Default|\n|--|--|--|--|\n|`type`|Type of pressure source to create|string||\n|`supported?`|Whether the pressure source should be configured as supported|boolean|`true`|\n\n## Compute Pressure Protocol > ### createVirtualPressureSource > #### Response\n\n`null`\n\n## Compute Pressure Protocol > ### updateVirtualPressureSource\n\n```\nPOST /session/:sessionId/pressuresource/:pressureSourceType\n```\n\n> Compute Pressure documentation: [Update Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#update-virtual-pressure-source)\n\nUpdates the state of a virtual pressure source with the type identified by `:pressureSourceType`.","metadata":{"headerPath":"","sectionCount":10,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Compute Pressure Protocol > ### updateVirtualPressureSource > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`sample`|Pressure state. Supported values are `nominal`, `fair`, `serious`, or `critical`.|string|\n\n## Compute Pressure Protocol > ### updateVirtualPressureSource > #### Response\n\n`null`\n\n## Compute Pressure Protocol > ### deleteVirtualPressureSource\n\n```\nDELETE /session/:sessionId/pressuresource/:pressureSourceType\n```\n\n> Compute Pressure documentation: [Delete Virtual Pressure Source](https://www.w3.org/TR/compute-pressure/#delete-virtual-pressure-source)\n\nDeletes the virtual pressure source with the type identified by `:pressureSourceType`.\n\n## Compute Pressure Protocol > ### deleteVirtualPressureSource > #### Response\n\n`null`\n\n## Custom Handlers Protocol\n\nThe [Custom Handlers protocol](https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation)\nis an extension of the W3C WebDriver protocol, defined by the HTML Standard specification.\n\n## Custom Handlers Protocol > ### setRPHRegistrationMode\n\n```\nPOST /session/:sessionId/custom-handlers/set-mode\n```\n\n> Custom Handlers documentation: [Set RPH Registration Mode](https://html.spec.whatwg.org/multipage/system-state.html#user-agent-automation)\n\nSets the protocol handler automation mode, for processing registrations of custom protocol handlers.\nBy default, this mode is set to `none`.\n\n## Custom Handlers Protocol > ### setRPHRegistrationMode > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`mode`|Automation mode to set. Supported values are `autoAccept`, `autoReject`, or `none`.|string|\n\n## Custom Handlers Protocol > ### setRPHRegistrationMode > #### Response\n\n`null`\n\n## Device Posture Protocol\n\nThe [Device Posture protocol](https://www.w3.org/TR/device-posture/) is an extension of the W3C\nWebDriver protocol.\n\n## Device Posture Protocol > ### setDevicePosture\n\n```\nPOST /session/:sessionId/deviceposture\n```\n\n> Device Posture documentation: [Set Device Posture](https://www.w3.org/TR/device-posture/#set-device-posture)\n\nSets the device posture, overriding the posture set by the device hardware.\n\n## Device Posture Protocol > ### setDevicePosture > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`posture`|Posture to which the device should be set. Supported values are `continuous` or `folded`.|string|\n\n## Device Posture Protocol > ### setDevicePosture > #### Response\n\n`null`","metadata":{"headerPath":"## Compute Pressure Protocol > ### updateVirtualPressureSource > #### Parameters","sectionCount":12,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Device Posture Protocol > ### clearDevicePosture\n\n```\nDELETE /session/:sessionId/deviceposture\n```\n\n> Device Posture documentation: [Clear Device Posture](https://www.w3.org/TR/device-posture/#clear-device-posture)\n\nClears the previously set device posture, returning posture control back to the device hardware.\n\n## Device Posture Protocol > ### clearDevicePosture > #### Response\n\n`null`\n\n## Federated Credential Management Protocol\n\nThe [Federated Credential Management protocol](https://www.w3.org/TR/fedcm-1) (FedCM) is an\nextension of the W3C WebDriver protocol. Clients can enable this protocol by using the\n[`fedcm:accounts`](https://www.w3.org/TR/fedcm-1/#webdriver-capability) capability.\n\n## Federated Credential Management Protocol > ### fedCMCancelDialog\n\n```\nPOST /session/:sessionId/fedcm/canceldialog\n```\n\n> FedCM documentation: [Cancel Dialog](https://www.w3.org/TR/fedcm-1/#webdriver-canceldialog)\n\nCancels the currently open FedCM dialog.\n\n## Federated Credential Management Protocol > ### fedCMCancelDialog > #### Response\n\n`null`\n\n## Federated Credential Management Protocol > ### fedCMSelectAccount\n\n```\nPOST /session/:sessionId/fedcm/selectaccount\n```\n\n> FedCM documentation: [Select Account](https://www.w3.org/TR/fedcm-1/#webdriver-selectaccount)\n\nSelects an account to use for the currently open FedCM dialog.\n\n## Federated Credential Management Protocol > ### fedCMSelectAccount > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`accountIndex`|Index of the account in the list of available accounts|number|\n\n## Federated Credential Management Protocol > ### fedCMSelectAccount > #### Response\n\n`null`\n\n## Federated Credential Management Protocol > ### fedCMClickDialogButton\n\n```\nPOST /session/:sessionId/fedcm/clickdialogbutton\n```\n\n> FedCM documentation: [Click Dialog Button](https://www.w3.org/TR/fedcm-1/#webdriver-clickdialogbutton)\n\nClicks a button in the currently open FedCM dialog.\n\n## Federated Credential Management Protocol > ### fedCMClickDialogButton > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`dialogButton`|Identifier of the button to click. Must be set to `ConfirmIdpLoginContinue`.|string|\n\n## Federated Credential Management Protocol > ### fedCMClickDialogButton > #### Response\n\n`null`","metadata":{"headerPath":"## Device Posture Protocol > ### clearDevicePosture","sectionCount":11,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Federated Credential Management Protocol > ### fedCMGetAccounts\n\n```\nGET /session/:sessionId/fedcm/accountlist\n```\n\n> FedCM documentation: [Account List](https://www.w3.org/TR/fedcm-1/#webdriver-accountlist)\n\nRetrieves all accounts that the user can select in the currently open FedCM dialog.\n\n## Federated Credential Management Protocol > ### fedCMGetAccounts > #### Response\n\n`FedCMAccount[]` - an array of objects, where each object includes the following properties:\n\n|<div style=\"width:10em\">Name</div>|Description|Type|\n|--|--|--|\n|`accountId`|Account ID|string|\n|`email`|Account email|string|\n|`name`|Account name|string|\n|`givenName?`|Account given name|string|\n|`pictureUrl?`|Account picture URL|string|\n|`idpConfigUrl`|URL of the identity provider configuration file|string|\n|`loginState`|Login state. Set to `SignUp` if the account is not connected, otherwise `SignIn`.|string|\n|`termsOfServiceUrl?`|Terms of Service URL of the website, if `loginState` is set to `SignUp`|string|\n|`privacyPolicyUrl?`|Privacy Policy URL of the website, if `loginState` is set to `SignUp`|string|\n\n## Federated Credential Management Protocol > ### fedCMGetTitle\n\n```\nGET /session/:sessionId/fedcm/gettitle\n```\n\n> FedCM documentation: [Get Title](https://www.w3.org/TR/fedcm-1/#webdriver-gettitle)\n\nRetrieves the title and subtitle (if one exists) of the currently open FedCM dialog.\n\n## Federated Credential Management Protocol > ### fedCMGetTitle > #### Response\n\n`FedCMDialogTitle` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`title`|Dialog title|string|\n|`subtitle?`|Dialog subtitle|string|\n\n## Federated Credential Management Protocol > ### fedCMGetDialogType\n\n```\nGET /session/:sessionId/fedcm/getdialogtype\n```\n\n> FedCM documentation: [Get Dialog Type](https://www.w3.org/TR/fedcm-1/#webdriver-getdialogtype)\n\nRetrieves the type of the currently open FedCM dialog.\n\n## Federated Credential Management Protocol > ### fedCMGetDialogType > #### Response\n\n`string` - can be set to `AutoReauthn`, `AccountChooser`, or `ConfirmIdpLogin`\n\n## Federated Credential Management Protocol > ### fedCMSetDelayEnabled\n\n```\nPOST /session/:sessionId/fedcm/setdelayenabled\n```\n\n> FedCM documentation: [Set Delay Enabled](https://www.w3.org/TR/fedcm-1/#webdriver-setdelayenabled)\n\nSets the state of the promise rejection delay, which is used to prevent information leakage about\nthe logged in state of the user.","metadata":{"headerPath":"## Federated Credential Management Protocol > ### fedCMGetAccounts","sectionCount":7,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Federated Credential Management Protocol > ### fedCMSetDelayEnabled > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`enabled`|Whether to enable the promise rejection delay|boolean|\n\n## Federated Credential Management Protocol > ### fedCMSetDelayEnabled > #### Response\n\n`null`\n\n## Federated Credential Management Protocol > ### fedCMResetCooldown\n\n```\nPOST /session/:sessionId/fedcm/resetcooldown\n```\n\n> FedCM documentation: [Reset Cooldown](https://www.w3.org/TR/fedcm-1/#webdriver-resetcooldown)\n\nResets the cooldown delay used after dismissing a FedCM dialog.\n\n## Federated Credential Management Protocol > ### fedCMResetCooldown > #### Response\n\n`null`\n\n## Generic Sensor Protocol\n\nThe [Generic Sensor protocol](https://www.w3.org/TR/generic-sensor/) is an extension of the W3C\nWebDriver protocol.\n\n## Generic Sensor Protocol > ### createVirtualSensor\n\n```\nPOST /session/:sessionId/sensor\n```\n\n> Generic Sensor documentation: [Create Virtual Sensor](https://www.w3.org/TR/generic-sensor/#create-virtual-sensor-command)\n\nCreates a new virtual sensor.\n\n## Generic Sensor Protocol > ### createVirtualSensor > #### Parameters\n\n|<div style=\"width:12em\">Name</div>|Description|Type|Default|\n|--|--|--|--|\n|`type`|Type of sensor to create|string||\n|`connected?`|Whether the sensor should be configured as connected|boolean|`true`|\n|`maxSamplingFrequency?`|Maximum sensor sampling frequency|number||\n|`minSamplingFrequency?`|Minimum sensor sampling frequency|number||\n\n## Generic Sensor Protocol > ### createVirtualSensor > #### Response\n\n`null`\n\n## Generic Sensor Protocol > ### getVirtualSensorInfo\n\n```\nGET /session/:sessionId/sensor/:sensorType\n```\n\n> Generic Sensor documentation: [Get Virtual Sensor Information](https://www.w3.org/TR/generic-sensor/#get-virtual-sensor-information-command)\n\nRetrieves information about the virtual sensor with the type identified by `:sensorType`.\n\n## Generic Sensor Protocol > ### getVirtualSensorInfo > #### Response\n\n`GetVirtualSensorInfoResponse` - an object containing the `requestedSamplingFrequency` key, whose\nvalue is the requested sampling frequency of the sensor type\n\n## Generic Sensor Protocol > ### updateVirtualSensorReading\n\n```\nPOST /session/:sessionId/sensor/:sensorType\n```\n\n> Generic Sensor documentation: [Update Virtual Sensor Reading](https://www.w3.org/TR/generic-sensor/#update-virtual-sensor-reading-command)\n\nUpdates the virtual sensor with the type identified by `:sensorType` with a new reading.","metadata":{"headerPath":"## Federated Credential Management Protocol > ### fedCMSetDelayEnabled > #### Parameters","sectionCount":11,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Generic Sensor Protocol > ### updateVirtualSensorReading > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`reading`|Object containing reading properties specific to the sensor type|object|\n\n## Generic Sensor Protocol > ### updateVirtualSensorReading > #### Response\n\n`null`\n\n## Generic Sensor Protocol > ### deleteVirtualSensor\n\n```\nDELETE /session/:sessionId/sensor/:sensorType\n```\n\n> Generic Sensor documentation: [Delete Virtual Sensor](https://www.w3.org/TR/generic-sensor/#delete-virtual-sensor-command)\n\nDeletes the virtual sensor with the type identified by `:sensorType`.\n\n## Generic Sensor Protocol > ### deleteVirtualSensor > #### Response\n\n`null`\n\n## Permissions Protocol\n\nThe [Permissions protocol](https://www.w3.org/TR/permissions/) is an extension of the W3C WebDriver\nprotocol.\n\n## Permissions Protocol > ### setPermissions\n\n```\nPOST /session/:sessionId/permissions\n```\n\n> Permissions documentation: [Set Permission](https://www.w3.org/TR/permissions/#webdriver-command-set-permission)\n\nSimulates user modification of the permission state of a PermissionDescriptor (a permissible feature\nwith optional additional properties).\n\n## Permissions Protocol > ### setPermissions > #### Parameters\n\n|<div style=\"width:6em\">Name</div>|Description|Type|\n|--|--|--|\n|`descriptor`|Object specifying the feature name in its `name` key, along with any other keys for additional properties|object|\n|`state`|New permission state for this descriptor. Supported values are: `granted`, `denied`, or `prompt`.|string|\n\n## Permissions Protocol > ### setPermissions > #### Response\n\n`null`\n\n## Reporting Protocol\n\nThe [Reporting protocol](https://www.w3.org/TR/reporting-1/) is an extension of the W3C WebDriver\nprotocol.\n\n## Reporting Protocol > ### generateTestReport\n\n```\nPOST /session/:sessionId/reporting/generate_test_report\n```\n\n> Reporting documentation: [Generate Test Report](https://www.w3.org/TR/reporting-1/#generate-test-report-command)\n\nSimulates the generation of a test report, which can be retrieved by registered reporting observers.\n\n## Reporting Protocol > ### generateTestReport > #### Parameters\n\n|Name|Description|Type|Default|\n|--|--|--|--|\n|`message`|Message displayed in the report|string||\n|`group?`|Destination group to deliver the report to|string|`default`|\n\n## Reporting Protocol > ### generateTestReport > #### Response\n\n`null`","metadata":{"headerPath":"## Generic Sensor Protocol > ### updateVirtualSensorReading > #### Parameters","sectionCount":12,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Secure Payment Confirmation Protocol\n\nThe [Secure Payment Confirmation protocol](https://www.w3.org/TR/secure-payment-confirmation) (SPC)\nis an extension of the W3C WebDriver protocol.\n\n## Secure Payment Confirmation Protocol > ### setSPCTransactionMode\n\n```\nPOST /session/:sessionId/secure-payment-confirmation/set-mode\n```\n\n> SPC documentation: [Set SPC Transaction Mode](https://www.w3.org/TR/secure-payment-confirmation/#sctn-automation-set-spc-transaction-mode)\n\nSets the transaction automation mode, for automated handling of transaction confirmation prompts.\nBy default, this mode is set to `none`.\n\n## Secure Payment Confirmation Protocol > ### setSPCTransactionMode > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`mode`|Automation mode to set. Supported values are `autoAccept`, `autoChooseToAuthAnotherWay`, `autoReject`, or `autoOptOut`.|string|\n\n## Secure Payment Confirmation Protocol > ### setSPCTransactionMode > #### Response\n\n`null`\n\n## Selenium Protocol\n\nThe Selenium protocol is an extension of the W3C WebDriver protocol, supported in Appium clients\nbased on Selenium.\n\n!!! warning\n\n Endpoints specified by this protocol are not officially documented.\n\n## Selenium Protocol > ### getLog\n\n```\nPOST /session/:sessionId/se/log\n```\n\nRetrieves the logs for a given log type. Supported log types depend on the driver, and can be\nretrieved using the [`getLogTypes`](#getlogtypes) endpoint.\n\n## Selenium Protocol > ### getLog > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`type`|Type of log to retrieve|string|\n\n## Selenium Protocol > ### getLog > #### Response\n\n`GetLogEntry[]` - an array of log entries.\n\nTypically a log entry is an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`level`|Level at which the message was logged|string|\n|`message`|Contents of the actual log message|string|\n|`timestamp`|Message timestamp (in milliseconds) in Unix format|number|\n\n## Selenium Protocol > ### getLogTypes\n\n```\nGET /session/:sessionId/se/log/types\n```\n\nRetrieves the available log types that can be used to call the [`getLog`](#getlog) endpoint.\n\n## Selenium Protocol > ### getLogTypes > #### Response\n\n`string[]` - an array of log types","metadata":{"headerPath":"## Secure Payment Confirmation Protocol","sectionCount":10,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Web Authentication Protocol\n\nThe [Web Authentication protocol](https://w3c.github.io/webauthn/) (WebAuthn) is an extension of\nthe W3C WebDriver protocol. Clients can enable this protocol by using the\n[`webauthn:virtualAuthenticators`](https://w3c.github.io/webauthn/#sctn-automation-webdriver-capability)\ncapability.\n\n## Web Authentication Protocol > ### addVirtualAuthenticator\n\n```\nPOST /session/:sessionId/webauthn/authenticator\n```\n\n> WebAuthn documentation: [Add Virtual Authenticator](https://w3c.github.io/webauthn/#add-virtual-authenticator)\n\nCreates a software [virtual authenticator](https://w3c.github.io/webauthn/#virtual-authenticators).\n\n## Web Authentication Protocol > ### addVirtualAuthenticator > #### Parameters\n\n|<div style=\"width:11em\">Name</div>|Description|Type|Default|\n|--|--|--|--|\n|`isUserConsenting?`|Whether to always grant user consent|boolean|true|\n|`isUserVerified?`|Whether to always succeed in user verification. Ignored if `hasUserVerification` is set to `false`.|boolean|false|\n|`hasResidentKey?`|Whether client-side discoverable credentials are supported|boolean|false|\n|`hasUserVerification?`|Whether user verification is supported|boolean|false|\n|`protocol`|Protocol of this authenticator. Supported values are: `ctap1/u2f`, `ctap2`, or `ctap2_1`.|string||\n|`transport`|Type of transport used to communicate with clients. Supported values are: `ble`, `hybrid`, `internal`, `nfc`, `smart-card`, or `usb`.|string||\n\n## Web Authentication Protocol > ### addVirtualAuthenticator > #### Response\n\n`string` - the ID of the created authenticator\n\n## Web Authentication Protocol > ### removeVirtualAuthenticator\n\n```\nDELETE /session/:sessionId/webauthn/authenticator/:authenticatorId\n```\n\n> WebAuthn documentation: [Remove Virtual Authenticator](https://w3c.github.io/webauthn/#remove-virtual-authenticator)\n\nRemoves the virtual authenticator identified by `:authenticatorId`.\n\n## Web Authentication Protocol > ### removeVirtualAuthenticator > #### Response\n\n`null`\n\n## Web Authentication Protocol > ### addAuthCredential\n\n```\nPOST /session/:sessionId/webauthn/authenticator/:authenticatorId/credential\n```\n\n> WebAuthn documentation: [Add Credential](https://w3c.github.io/webauthn/#add-credential)\n\nInjects a [Public Key Credential Source](https://w3c.github.io/webauthn/#public-key-credential-source)\ninto the virtual authenticator identified by `:authenticatorId`.","metadata":{"headerPath":"## Web Authentication Protocol","sectionCount":7,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Web Authentication Protocol > ### addAuthCredential > #### Parameters\n\n|<div style=\"width:11em\">Name</div>|Description|Type|\n|--|--|--|\n|`credentialId`|Credential ID, in Base64url encoding|string|\n|`isResidentCredential`|Whether to create a client-side discoverable credential. If set to `false`, a server-side credential is created instead.|boolean|\n|`privateKey`|Asymmetric key package containing a single private key, in Base64url encoding|string|\n|`rpId`|Relying Party ID the credential is scoped to|string|\n|`signCount?`|Initial value for the signature counter. Set to `0` if omitted.|number|\n|`userHandle?`|User handle associated with the credential, in Base64url encoding. Set to `null` if omitted.|string|\n\n## Web Authentication Protocol > ### addAuthCredential > #### Response\n\n`null`\n\n## Web Authentication Protocol > ### getAuthCredential\n\n```\nGET /session/:sessionId/webauthn/authenticator/:authenticatorId/credentials\n```\n\n> WebAuthn documentation: [Get Credentials](https://w3c.github.io/webauthn/#get-credentials)\n\nRetrieves all Public Key Credential Sources stored in the virtual authenticator identified by\n`:authenticatorId`.\n\n## Web Authentication Protocol > ### getAuthCredential > #### Response\n\n`Credential[]` - an array of credential objects. Each object has the following properties:\n\n|<div style=\"width:11em\">Name</div>|Description|Type|Default|\n|--|--|--|--|\n|`credentialId`|Credential ID, in Base64url encoding|string||\n|`isResidentCredential`|Whether the credential is client-side discoverable (`true`) or server-side (`false`)|boolean||\n|`largeBlob`|Large, per-credential blog, in Base64url encoding|string|`null`|\n|`privateKey`|Asymmetric key package containing a single private key, in Base64url encoding|string||\n|`rpId`|Relying Party ID the credential is scoped to|string||\n|`signCount`|Initial value for the signature counter|number|`0`|\n|`userHandle`|User handle associated with the credential, in Base64url encoding|string|`null`|\n\n## Web Authentication Protocol > ### removeAuthCredential\n\n```\nDELETE /session/:sessionId/webauthn/authenticator/:authenticatorId/credentials/:credentialId\n```\n\n> WebAuthn documentation: [Remove Credential](https://w3c.github.io/webauthn/#remove-credential)\n\nRemoves the Public Key Credential Source identified by `:credentialId` from the virtual authenticator\nidentified by `:authenticatorId`.\n\n## Web Authentication Protocol > ### removeAuthCredential > #### Response\n\n`null`","metadata":{"headerPath":"## Web Authentication Protocol > ### addAuthCredential > #### Parameters","sectionCount":6,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"## Web Authentication Protocol > ### removeAllAuthCredentials\n\n```\nDELETE /session/:sessionId/webauthn/authenticator/:authenticatorId/credentials\n```\n\n> WebAuthn documentation: [Remove All Credentials](https://w3c.github.io/webauthn/#remove-all-credentials)\n\nRemoves all Public Key Credential Sources from the virtual authenticator identified by\n`:authenticatorId`.\n\n## Web Authentication Protocol > ### removeAllAuthCredentials > #### Response\n\n`null`\n\n## Web Authentication Protocol > ### setUserAuthVerified\n\n```\nPOST /session/:sessionId/webauthn/authenticator/:authenticatorId/uv\n```\n\n> WebAuthn documentation: [Set User Verified](https://w3c.github.io/webauthn/#set-user-verified)\n\nSets the `isUserVerified` property of the virtual authenticator identified by `:authenticatorId`.\n\n## Web Authentication Protocol > ### setUserAuthVerified > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`isUserVerified`|Whether to always succeed in user verification|boolean|\n\n## Web Authentication Protocol > ### setUserAuthVerified > #### Response\n\n`null`","metadata":{"headerPath":"## Web Authentication Protocol > ### removeAllAuthCredentials","sectionCount":5,"filename":"others.md","relativePath":"appium/packages/appium/docs/en/reference/api/others.md"}},{"pageContent":"---\ntitle: Plugin Endpoints\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav .md-nav {\n display: none;\n }\n</style>\n\nThe following is a list of endpoints added or modified by official Appium plugins.\n\n## Execute Driver Plugin\n\n## Execute Driver Plugin > ### executeDriverScript\n\n```\nPOST /session/:sessionId/appium/execute_driver\n```\n\nExecutes a driver script in a child process.\n\n## Execute Driver Plugin > ### executeDriverScript > #### Parameters\n\n|Name|Description|Type|Default|\n|--|--|--|--|\n|`script`|Script to be executed|string||\n|`type?`|Name of the library executing the script|string|`webdriverio`|\n|`timeout?`|Timeout (in milliseconds) for the script process|number|`3600000`|\n\n## Execute Driver Plugin > ### executeDriverScript > #### Response\n\n`RunScriptResult` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`result`|Result returned by the script|any|\n|`logs`|Logs generated during script execution|object|\n\n## Images Plugin\n\n## Images Plugin > ### compareImages\n\n```\nPOST /session/:sessionId/appium/compare_images\n```\n\nCompares two images using the specified mode of comparison:\n\n* `matchFeatures`: whether `firstImage` is a rotated, scaled, or otherwise modified version of `secondImage`\n* `matchTemplate`: whether `firstImage` contains one or more occurrences of `secondImage`\n* `getSimilarity`: calculate similarity score between two images of equal size","metadata":{"headerPath":"","sectionCount":7,"filename":"plugins.md","relativePath":"appium/packages/appium/docs/en/reference/api/plugins.md"}},{"pageContent":"## Images Plugin > ### compareImages > #### Parameters\n\n|<div style=\"width:7em\">Name</div>|Description|Type|Default|\n|--|--|--|--|\n|`mode`|Mode of comparison. Supported values are: `matchFeatures`, `getSimilarity`, or `matchTemplate`.|string||\n|`firstImage`|Base64-encoded image file|string or Buffer||\n|`secondImage`|Base64-encoded image file|string or Buffer||\n|`options?`|Options specific to the `mode` value (see below)|object|`{}`|\n\n**`options` for `mode=matchFeatures`**\n\n|<div style=\"width:10em\">Name</div>|Description|Type|<div style=\"width:6em\">Default</div>|\n|--|--|--|--|\n|`detectorName?`|Name of the OpenCV feature detector to use. Supported values are: `AKAZE`, `AgastFeatureDetector`, `BRISK`, `FastFeatureDetector`, `GFTTDetector`, `KAZE`, `MSER`, or `ORB`.|string|`ORB`|\n|`goodMatchesFactor?`|Maximum number of 'good' matches; or a function accepting current distance, min distance and max distance, and returning a boolean indicating whether the match should be included or not.|number or function||\n|`matchFunc?`|Name of the OpenCV descriptor matcher to use. Supported values are: `FlannBased`, `BruteForce`, `BruteForce-L1`, `BruteForce-Hamming`, `BruteForce-HammingLUT`, or `BruteForce-SL2`.|string|`BruteForce`|\n|`visualize?`|Whether to include an image of the matcher visualization in the response|boolean|`false`|\n\n**`options` for `mode=matchTemplate`**\n\n|<div style=\"width:13em\">Name</div>|Description|Type|<div style=\"width:9em\">Default</div>|\n|--|--|--|--|\n|`matchNeighbourThreshold?`|Maximum pixel distance between two matches to consider them the same match|number|`10`|\n|`method?`|Name of the OpenCV template matching method to use. Supported values are: `TM_CCOEFF`, `TM_CCOEFF_NORMED`, `TM_CCORR`, `TM_CCORR_NORMED`, `TM_SQDIFF`, or `TM_SQDIFF_NORMED`.|string|`TM_CCOEFF_NORMED`|\n|`multiple?`|Whether to look for multiple occurrences of the image|boolean|`false`|\n|`threshold?`|Threshold to use for accepting/rejecting a match|number|`0.5`|\n|`visualize?`|Whether to include an image of the matcher visualization in the response|boolean|`false`|\n\n**`options` for `mode=getSimilarity`**\n\n|<div style=\"width:6em\">Name</div>|Description|Type|<div style=\"width:9em\">Default</div>|\n|--|--|--|--|\n|`method?`|Name of the OpenCV template matching method to use. Supported values are: `TM_CCOEFF`, `TM_CCOEFF_NORMED`, `TM_CCORR`, `TM_CCORR_NORMED`, `TM_SQDIFF`, or `TM_SQDIFF_NORMED`.|string|`TM_CCOEFF_NORMED`|\n|`visualize?`|Whether to include an image of the matcher visualization in the response|boolean|`false`|","metadata":{"headerPath":"## Images Plugin > ### compareImages > #### Parameters","sectionCount":1,"recursiveSplit":true,"filename":"plugins.md","relativePath":"appium/packages/appium/docs/en/reference/api/plugins.md"}},{"pageContent":"## Images Plugin > ### compareImages > #### Response\n\n`ComparisonResult` - an object whose properties depend on the `mode` input parameter:\n\n**`ComparisonResult` for `mode=matchFeatures`**\n\n|<div style=\"width:8em\">Name</div>|Description|Type|\n|--|--|--|\n|`count`|Number of matched edges on both images, after applying `goodMatchesFactor` (if specified).|number|\n|`points1`|Array of matching points on `firstImage`|`{x, y}[]`|\n|`points2`|Array of matching points on `secondImage`|`{x, y}[]`|\n|`rect1`|Bounding rectangle for `points1`|`{x, y, width, height}`|\n|`rect2`|Bounding rectangle for `points2`|`{x, y, width, height}`|\n|`totalCount`|Total number of matched edges on both images, before applying `goodMatchesFactor` (if specified)|number|\n|`visualization?`|Image of the matcher visualization. Only included if the `visualize` input option was enabled.|Buffer|\n\n**`ComparisonResult` for `mode=matchTemplate`**\n\n|<div style=\"width:8em\">Name</div>|Description|Type|\n|--|--|--|\n|`rect`|Region of `firstImage` where a match was found for `secondImage`|`{x, y, width, height}`|\n|`multiple?`|Array of all comparison results. Only included if the `multiple` input option was enabled.|`{rect, score, visualization?}`|\n|`score`|Similarity score between both images in the range `[0.0, 1.0]`|number|\n|`visualization?`|Image of the matcher visualization. Only included if the `visualize` input option was enabled.|Buffer|\n\n**`ComparisonResult` for `mode=getSimilarity`**\n\n|<div style=\"width:8em\">Name</div>|Description|Type|\n|--|--|--|\n|`score`|Similarity score between both images in the range `[0.0, 1.0]`|number|\n|`visualization?`|Image of the matcher visualization. Only included if the `visualize` input option was enabled.|Buffer|\n\n## Images Plugin > ### findElement\n\n```\nPOST /session/:sessionId/element\n```\n\nModifies the [`findElement`](./webdriver.md#findelement) endpoint:\n\n* Adds `-image` to the supported values for the `using` parameter (the location strategy)\n\n## Images Plugin > ### findElements\n\n```\nPOST /session/:sessionId/elements\n```\n\nModifies the [`findElements`](./webdriver.md#findelements) endpoint:\n\n* Adds `-image` to the supported values for the `using` parameter (the location strategy)","metadata":{"headerPath":"## Images Plugin > ### compareImages > #### Response","sectionCount":3,"filename":"plugins.md","relativePath":"appium/packages/appium/docs/en/reference/api/plugins.md"}},{"pageContent":"## Images Plugin > ### performActions\n\n```\nPOST /session/:sessionId/actions\n```\n\nModifies the [`performActions`](./webdriver.md#performactions) endpoint:\n\n* If any action in `actions` includes `origin`, whose value is an image element:\n * Removes the `origin` property\n * Increments the `x` and `y` properties by the center coordinates of the image element\n\n## Relaxed Caps Plugin\n\n## Relaxed Caps Plugin > ### createSession\n\n```\nPOST /session\n```\n\nModifies the [`createSession`](./webdriver.md#createsession) endpoint:\n\n* Adds the `appium:` prefix to all keys in `capabilities`, unless they match a standard W3C\n capability, or already have any prefix\n\n## Storage Plugin\n\n!!! tip\n\n All endpoints for this plugin can be invoked without creating a session, allowing you to prepare\n your test environment in advance.\n\n## Storage Plugin > ### addStorageItem\n\n```\nPOST /storage/add\n```\n\nAdds a new file to the storage.\n\n## Storage Plugin > ### addStorageItem > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`name`|Name used for saving the file (must not include path separator characters)|string|\n|`sha1`|SHA1 hash of the file to be uploaded|string|\n\n## Storage Plugin > ### addStorageItem > #### Response\n\n`AddRequestResult` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`ttlMs`|Timeout (in milliseconds) for both web sockets to remain active, or for a file payload to be successfully uploaded|number|\n|`ws.events`|Path for the events web socket used to notify about upload success or failure|string|\n|`ws.stream`|Path for the streaming web socket used to upload the file content|string|\n\nExample:\n```json\n{\n \"ws\": {\n \"stream\": \"/storage/add/ccc963411b2621335657963322890305ebe96186/stream\",\n \"events\": \"/storage/add/ccc963411b2621335657963322890305ebe96186/events\"\n },\n \"ttlMs\": 300000\n}\n```\n\n## Storage Plugin > ### deleteStorageItem\n\n```\nPOST /storage/delete\n```\n\nDeletes a file in the storage.\n\n## Storage Plugin > ### deleteStorageItem > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`name`|Name of the file to be deleted|string|\n\n## Storage Plugin > ### deleteStorageItem > #### Response\n\n`boolean` - `true` upon successful file deletion, or `false` if the file does not exist in\nthe storage\n\n## Storage Plugin > ### listStorageItems\n\n```\nGET /storage/list\n```\n\nList all files present in the storage.","metadata":{"headerPath":"## Images Plugin > ### performActions","sectionCount":11,"filename":"plugins.md","relativePath":"appium/packages/appium/docs/en/reference/api/plugins.md"}},{"pageContent":"## Storage Plugin > ### listStorageItems > #### Response\n\n`List<StorageItem>` - a list of items, where each item has the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`name`|Name of the file in the storage|string|\n|`path`|Full path to the file on the remote file system|string|\n|`size`|File size in bytes|number|\n\n## Storage Plugin > ### resetStorage\n\n```\nPOST /storage/reset\n```\n\nDeletes all uploaded files and stops any incomplete uploads.\nIf the [`APPIUM_STORAGE_KEEP_ALL` flag](../cli/env-vars.md) is set, all uploaded files will be\npreserved, and only the incomplete uploads will be stopped.\n\n## Storage Plugin > ### resetStorage > #### Response\n\n`void`\n\n## Universal XML Plugin\n\n## Universal XML Plugin > ### findElement\n\n```\nPOST /session/:sessionId/element\n```\n\nModifies the [`findElement`](./webdriver.md#findelement) endpoint:\n\n* Adds support for universal node/attribute names for the `value` parameter (the selector)\n\n## Universal XML Plugin > ### findElements\n\n```\nPOST /session/:sessionId/elements\n```\n\nModifies the [`findElements`](./webdriver.md#findelements) endpoint:\n\n* Adds support for universal node/attribute names for the `value` parameter (the selector)\n\n## Universal XML Plugin > ### getPageSource\n\n```\nGET /session/:sessionId/source\n```\n\nModifies the [`getPageSource`](./webdriver.md#getpagesource) endpoint:\n\n* After retrieving the result, translates node/attribute names to their universal names","metadata":{"headerPath":"## Storage Plugin > ### listStorageItems > #### Response","sectionCount":7,"filename":"plugins.md","relativePath":"appium/packages/appium/docs/en/reference/api/plugins.md"}},{"pageContent":"---\ntitle: WebDriver Protocol\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav {\n display: none;\n }\n</style>\n\nThe following is a list of [W3C WebDriver protocol](https://w3c.github.io/webdriver/) endpoints\nsupported in Appium.\n\n!!! info\n\n Most WebDriver endpoints are not implemented within Appium itself, and are instead proxied\n directly to the driver, which is responsible for the actual endpoint implementation.\n\n### createSession\n\n```\nPOST /session\n```\n\n> WebDriver documentation: [New Session](https://w3c.github.io/webdriver/#new-session)\n\nCreates a new WebDriver session.\n\nAppium implements a modified version of this endpoint for historical reasons. While the W3C\nendpoint only accepts 1 parameter, Appium's implementation allows up to 3 parameters, as this was\nrequired by the legacy JSON Wire Protocol (JSONWP). Since Appium 2, the JSONWP format is no longer\nsupported, and any of the 3 parameters can be used to specify the W3C capabilities.\n\n### createSession > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`w3cCapabilities1?`|Capabilities of the new session|`W3CDriverCaps`|\n|`w3cCapabilities2?`|Another location for the new session capabilities (legacy)|`W3CDriverCaps`|\n|`w3cCapabilities?`|Another location for the new session capabilities (legacy)|`W3CDriverCaps`|\n\n### createSession > #### Response\n\n`CreateResult` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`sessionId`|ID of the new session|string|\n|`capabilities`|Capabilities processed by the driver|object|\n\n### deleteSession\n\n```\nDELETE /session/:sessionId\n```\n\n> WebDriver documentation: [Delete Session](https://w3c.github.io/webdriver/#delete-session)\n\nCloses the current session.\n\n### deleteSession > #### Response\n\n`null`\n\n### getStatus\n\n```\nGET /status\n```\n\n> WebDriver documentation: [Status](https://w3c.github.io/webdriver/#status)\n\nRetrieves the current status of the Appium server.\n\n### getStatus > #### Response\n\n`GetStatusResult` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`build`|Implementation-specific information. For Appium, this is an object containing the `version` key, whose value matches the Appium server version.|`{version}`|\n|`message`|Explanation of the `ready` value|string|\n|`ready`|Whether the server is able to create new sessions|boolean|","metadata":{"headerPath":"","sectionCount":8,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### getTimeouts\n\n```\nGET /session/:sessionId/timeouts\n```\n\n> WebDriver documentation: [Get Timeouts](https://w3c.github.io/webdriver/#get-timeouts)\n\nRetrieves the timeout values of the current session.\n\n### getTimeouts > #### Response\n\n`GetTimeoutsResult` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`command`|Command timeout|number|\n|`implicit`|Implicit wait timeout|number|\n\n### timeouts\n\n```\nPOST /session/:sessionId/timeouts\n```\n\n> WebDriver documentation: [Set Timeouts](https://w3c.github.io/webdriver/#set-timeouts)\n\nSets the timeout values of the current session.\n\n### timeouts > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`implicit?`|Implicit wait timeout (in milliseconds)|number|\n|`pageLoad?`|Page load timeout (in milliseconds)|number|\n|`script?`|Script timeout (in milliseconds)|number|\n\n### timeouts > #### Response\n\n`null`\n\n### setUrl\n\n```\nPOST /session/:sessionId/url\n```\n\n> WebDriver documentation: [Navigate To](https://w3c.github.io/webdriver/#navigate-to)\n\nNavigates the current top-level browsing context to the specified URL.\n\n### setUrl > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`url`|URL to navigate to|string|\n\n### setUrl > #### Response\n\n`null`\n\n### getUrl\n\n```\nGET /session/:sessionId/url\n```\n\n> WebDriver documentation: [Get Current URL](https://w3c.github.io/webdriver/#get-current-url)\n\nRetrieves the URL of the current top-level browsing context.\n\n### getUrl > #### Response\n\n`string` - the current URL\n\n### back\n\n```\nPOST /session/:sessionId/back\n```\n\n> WebDriver documentation: [Back](https://w3c.github.io/webdriver/#back)\n\nNavigates backwards in the browser history, if possible.\n\n### back > #### Response\n\n`null`\n\n### forward\n\n```\nPOST /session/:sessionId/forward\n```\n\n> WebDriver documentation: [Forward](https://w3c.github.io/webdriver/#forward)\n\nNavigates forwards in the browser history, if possible.\n\n### forward > #### Response\n\n`null`\n\n### refresh\n\n```\nPOST /session/:sessionId/refresh\n```\n\n> WebDriver documentation: [Refresh](https://w3c.github.io/webdriver/#refresh)\n\nReloads the window of the current top-level browsing context.\n\n### refresh > #### Response\n\n`null`\n\n### title\n\n```\nGET /session/:sessionId/title\n```\n\n> WebDriver documentation: [Get Title](https://w3c.github.io/webdriver/#get-title)\n\nRetrieves the window title of the top-level browsing context.\n\n### title > #### Response\n\n`string` - the page title","metadata":{"headerPath":"### getTimeouts","sectionCount":18,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### getWindowHandle\n\n```\nGET /session/:sessionId/window\n```\n\n> WebDriver documentation: [Get Window Handle](https://w3c.github.io/webdriver/#get-window-handle)\n\nRetrieves the window handle of the top-level browsing context.\n\n### getWindowHandle > #### Response\n\n`string` - the window handle identifier\n\n### closeWindow\n\n```\nDELETE /session/:sessionId/window\n```\n\n> WebDriver documentation: [Close Window](https://w3c.github.io/webdriver/#close-window)\n\nCloses the current top-level browsing context.\n\n### closeWindow > #### Response\n\n`string[]` - an array of zero or more remaining window handle identifiers\n\n### setWindow\n\n```\nPOST /session/:sessionId/window\n```\n\n> WebDriver documentation: [Switch To Window](https://w3c.github.io/webdriver/#switch-to-window)\n\nSelects the top-level browsing context.\n\n### setWindow > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`handle`|Identifier for the window to switch to|string|\n\n### setWindow > #### Response\n\n`null`\n\n### getWindowHandles\n\n```\nGET /session/:sessionId/window/handles\n```\n\n> WebDriver documentation: [Get Window Handles](https://w3c.github.io/webdriver/#get-window-handles)\n\nRetrieves a list of window handles for every top-level browsing context.\n\n### getWindowHandles > #### Response\n\n`string[]` - an array of zero or more window handle identifiers\n\n### createNewWindow\n\n```\nPOST /session/:sessionId/window/new\n```\n\n> WebDriver documentation: [New Window](https://w3c.github.io/webdriver/#new-window)\n\nCreates a new window or tab.\n\n### createNewWindow > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`type`|Type of window to create (`window` or `tab`)|string|\n\n### createNewWindow > #### Response\n\n`NewWindow` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`handle`|ID of the created window handle|string|\n|`type`|Type of the created window (`window` or `tab`)|string|\n\n### setFrame\n\n```\nPOST /session/:sessionId/frame\n```\n\n> WebDriver documentation: [Switch To Frame](https://w3c.github.io/webdriver/#switch-to-frame)\n\nSelects the top-level or child browsing context as the current browsing context.\n\n### setFrame > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`id`|Identifier for the frame|null, number, or [`Element`](#response_23)|\n\n### setFrame > #### Response\n\n`null`","metadata":{"headerPath":"### getWindowHandle","sectionCount":15,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### switchToParentFrame\n\n```\nPOST /session/:sessionId/frame/parent\n```\n\n> WebDriver documentation: [Switch To Parent Frame](https://w3c.github.io/webdriver/#switch-to-parent-frame)\n\nSets the current browsing context to the parent of the current browsing context.\n\n### switchToParentFrame > #### Response\n\n`null`\n\n### getWindowRect\n\n```\nGET /session/:sessionId/window/rect\n```\n\n> WebDriver documentation: [Get Window Rect](https://w3c.github.io/webdriver/#get-window-rect)\n\nRetrieves the size and position of the current window.\n\n### getWindowRect > #### Response\n\n`Rect` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`height`|Window height|number|\n|`width`|Window width|number|\n|`x`|X-axis position of the top-left corner of the window|number|\n|`y`|Y-axis position of the top-left corner of the window|number|\n\n### setWindowRect\n\n```\nPOST /session/:sessionId/window/rect\n```\n\n> WebDriver documentation: [Set Window Rect](https://w3c.github.io/webdriver/#set-window-rect)\n\nSets the size and/or position of the current window.\n\n### setWindowRect > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`height?`|Window height|number|\n|`width?`|Window width|number|\n|`x?`|X-axis position of the top-left corner of the window|number|\n|`y?`|Y-axis position of the top-left corner of the window|number|\n\n### setWindowRect > #### Response\n\n[`Rect`](#response_18) - the new window size\n\n### maximizeWindow\n\n```\nPOST /session/:sessionId/window/maximize\n```\n\n> WebDriver documentation: [Maximize Window](https://w3c.github.io/webdriver/#maximize-window)\n\nMaximizes the current window.\n\n### maximizeWindow > #### Response\n\n[`Rect`](#response_18) - the new window size\n\n### minimizeWindow\n\n```\nPOST /session/:sessionId/window/minimize\n```\n\n> WebDriver documentation: [Minimize Window](https://w3c.github.io/webdriver/#minimize-window)\n\nMinimizes the current window.\n\n### minimizeWindow > #### Response\n\n[`Rect`](#response_18) - the new window size\n\n### fullScreenWindow\n\n```\nPOST /session/:sessionId/window/fullscreen\n```\n\n> WebDriver documentation: [Fullscreen Window](https://w3c.github.io/webdriver/#fullscreen-window)\n\nMakes the current window fullscreen.\n\n### fullScreenWindow > #### Response\n\n[`Rect`](#response_18) - the new window size\n\n### active\n\n```\nGET /session/:sessionId/element/active\n```\n\n> WebDriver documentation: [Get Active Element](https://w3c.github.io/webdriver/#get-active-element)\n\nRetrieves the currently focused element.","metadata":{"headerPath":"### switchToParentFrame","sectionCount":14,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### active > #### Response\n\n`Element` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`element-6066-11e4-a52e-4f735466cecf`|Element ID|string|\n|`ELEMENT`|Element ID (same value as `element-6066-11e4-a52e-4f735466cecf`). This key was used in the legacy Mobile JSON Wire Protocol (MJSONWP).|string|\n\n### elementShadowRoot\n\n```\nGET /session/:sessionId/element/:elementId/shadow\n```\n\n> WebDriver documentation: [Get Shadow Root](https://w3c.github.io/webdriver/#get-shadow-root)\n\nRetrieves the shadow root of the element identified by `:elementId`.\n\n### elementShadowRoot > #### Response\n\n`ShadowElement` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`shadow-6066-11e4-a52e-4f735466cecf`|Shadow root ID|string|\n\n### findElement\n\n```\nPOST /session/:sessionId/element\n```\n\n> WebDriver documentation: [Find Element](https://w3c.github.io/webdriver/#find-element)\n\nFinds the first element in the current browsing context that matches the provided selector and\nlocation strategy, starting from the root node.\n\n### findElement > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`using`|Location strategy to use when searching|string|\n|`value`|Selector used to find the element|string|\n\n### findElement > #### Response\n\n[`Element`](#response_23)\n\n### findElements\n\n```\nPOST /session/:sessionId/elements\n```\n\n> WebDriver documentation: [Find Elements](https://w3c.github.io/webdriver/#find-elements)\n\nFinds all elements in the current browsing context that match the provided selector and location\nstrategy, starting from the root node.\n\n### findElements > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`using`|Location strategy to use when searching|string|\n|`value`|Selector used to find the element|string|\n\n### findElements > #### Response\n\n`Element[]` - an array containing zero or more [`Element` objects](#response_23)\n\n### findElementFromElement\n\n```\nPOST /session/:sessionId/element/:elementId/element\n```\n\n> WebDriver documentation: [Find Element From Element](https://w3c.github.io/webdriver/#find-element-from-element)\n\nFinds the first element in the current browsing context that matches the provided selector and\nlocation strategy, starting from the element node identified by `:elementId`.\n\n### findElementFromElement > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`using`|Location strategy to use when searching|string|\n|`value`|Selector used to find the element|string|","metadata":{"headerPath":"### active > #### Response","sectionCount":11,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### findElementFromElement > #### Response\n\n[`Element`](#response_23)\n\n### findElementsFromElement\n\n```\nPOST /session/:sessionId/element/:elementId/elements\n```\n\n> WebDriver documentation: [Find Elements From Element](https://w3c.github.io/webdriver/#find-elements-from-element)\n\nFinds all elements in the current browsing context that match the provided selector and location\nstrategy, starting from the element node identified by `:elementId`.\n\n### findElementsFromElement > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`using`|Location strategy to use when searching|string|\n|`value`|Selector used to find the element|string|\n\n### findElementsFromElement > #### Response\n\n[`Element[]`](#response_26)\n\n### findElementFromShadowRoot\n\n```\nPOST /session/:sessionId/shadow/:shadowId/element\n```\n\n> WebDriver documentation: [Find Element From Shadow Root](https://w3c.github.io/webdriver/#find-element-from-shadow-root)\n\nFinds the first element in the current browsing context that matches the provided selector and\nlocation strategy, starting from the shadow root node identified by `:shadowId`.\n\n### findElementFromShadowRoot > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`using`|Location strategy to use when searching|string|\n|`value`|Selector used to find the element|string|\n\n### findElementFromShadowRoot > #### Response\n\n[`Element`](#response_23)\n\n### findElementsFromShadowRoot\n\n```\nPOST /session/:sessionId/shadow/:shadowId/elements\n```\n\n> WebDriver documentation: [Find Elements From Shadow Root](https://w3c.github.io/webdriver/#find-elements-from-shadow-root)\n\nFinds all elements in the current browsing context that match the provided selector and location\nstrategy, starting from the shadow root node identified by `:shadowId`.\n\n### findElementsFromShadowRoot > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`using`|Location strategy to use when searching|string|\n|`value`|Selector used to find the element|string|\n\n### findElementsFromShadowRoot > #### Response\n\n[`Element[]`](#response_26)\n\n### elementSelected\n\n```\nGET /session/:sessionId/element/:elementId/selected\n```\n\n> WebDriver documentation: [Is Element Selected](https://w3c.github.io/webdriver/#is-element-selected)\n\nDetermines if the element identified by `:elementId` is currently selected. This property is only\nrelevant to certain element types, such as checkboxes, radio buttons, or options.\n\n### elementSelected > #### Response\n\n`boolean` - `true` if the element is selected, otherwise `false`","metadata":{"headerPath":"### findElementFromElement > #### Response","sectionCount":12,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### elementDisplayed\n\n```\nGET /session/:sessionId/element/:elementId/displayed\n```\n\n> WebDriver documentation: [Element Displayedness](https://w3c.github.io/webdriver/#element-displayedness)\n\nDetermines if the element identified by `:elementId` is currently displayed.\n\n### elementDisplayed > #### Response\n\n`boolean` - `true` if the element is displayed, otherwise `false`\n\n### getAttribute\n\n```\nGET /session/:sessionId/element/:elementId/attribute/:name\n```\n\n> WebDriver documentation: [Get Element Attribute](https://w3c.github.io/webdriver/#get-element-attribute)\n\nRetrieves the value of the `:name` attribute for the element identified by `:elementId`.\n\n### getAttribute > #### Response\n\n`string` - the attribute value, or `null` if the attribute does not exist\n\n### getProperty\n\n```\nGET /session/:sessionId/element/:elementId/property/:name\n```\n\n> WebDriver documentation: [Get Element Property](https://w3c.github.io/webdriver/#get-element-property)\n\nRetrieves the value of the `:name` property for the element identified by `:elementId`.\n\n### getProperty > #### Response\n\n`string` - the property value, or `null` if the property does not exist\n\n### getCssProperty\n\n```\nGET /session/:sessionId/element/:elementId/css/:propertyName\n```\n\n> WebDriver documentation: [Get Element CSS Value](https://w3c.github.io/webdriver/#get-element-css-value)\n\nRetrieves the value of the `:propertyName` computed CSS property for the element identified by\n`:elementId`.\n\n### getCssProperty > #### Response\n\n`string` - the CSS property value, or `null` if the property does not exist\n\n### getText\n\n```\nGET /session/:sessionId/element/:elementId/text\n```\n\n> WebDriver documentation: [Get Element Text](https://w3c.github.io/webdriver/#get-element-text)\n\nRetrieves the text of the element identified by `:elementId`, as well as the text of its child\nelements (if any).\n\n### getText > #### Response\n\n`string` - the element text (including its child elements)\n\n### getName\n\n```\nGET /session/:sessionId/element/:elementId/name\n```\n\n> WebDriver documentation: [Get Element Tag Name](https://w3c.github.io/webdriver/#get-element-tag-name)\n\nRetrieves the tag name of the element identified by `:elementId`.\n\n### getName > #### Response\n\n`string` - the element tag name","metadata":{"headerPath":"### elementDisplayed","sectionCount":12,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### getElementRect\n\n```\nGET /session/:sessionId/element/:elementId/rect\n```\n\n> WebDriver documentation: [Get Element Rect](https://w3c.github.io/webdriver/#get-element-rect)\n\nRetrieves the dimensions and coordinates of the element identified by `:elementId`.\n\n### getElementRect > #### Response\n\n[`Rect`](#response_18)\n\n### elementEnabled\n\n```\nGET /session/:sessionId/element/:elementId/enabled\n```\n\n> WebDriver documentation: [Is Element Enabled](https://w3c.github.io/webdriver/#is-element-enabled)\n\nDetermines if the element identified by `:elementId` is currently enabled. This property is only\nrelevant to certain element types, such as buttons, input fields, checkboxes, etc.\n\n### elementEnabled > #### Response\n\n`boolean` - `true` if the element is enabled, otherwise `false`\n\n### getComputedRole\n\n```\nGET /session/:sessionId/element/:elementId/computedrole\n```\n\n> WebDriver documentation: [Get Computed Role](https://w3c.github.io/webdriver/#get-computed-role)\n\nRetrieves the computed [WAI-ARIA](https://w3c.github.io/aria/#introroles) role of the element\nidentified by `:elementId`.\n\n### getComputedRole > #### Response\n\n`string` - the element computed role\n\n### getComputedLabel\n\n```\nGET /session/:sessionId/element/:elementId/computedlabel\n```\n\n> WebDriver documentation: [Get Computed Label](https://w3c.github.io/webdriver/#get-computed-label)\n\nRetrieves the [accessible name](https://w3c.github.io/accname/#dfn-accessible-name) of the\nelement identified by `:elementId`.\n\n### getComputedLabel > #### Response\n\n`string` - the element accessible name\n\n### click\n\n```\nPOST /session/:sessionId/element/:elementId/click\n```\n\n> WebDriver documentation: [Element Click](https://w3c.github.io/webdriver/#element-click)\n\nClicks on the identified by `:elementId`.\n\n### click > #### Response\n\n`null`\n\n### clear\n\n```\nPOST /session/:sessionId/element/:elementId/clear\n```\n\n> WebDriver documentation: [Element Clear](https://w3c.github.io/webdriver/#element-clear)\n\nClears the identified by `:elementId`. This functionality is only relevant to certain element types,\nsuch as input fields.\n\n### clear > #### Response\n\n`null`\n\n### setValue\n\n```\nPOST /session/:sessionId/element/:elementId/value\n```\n\n> WebDriver documentation: [Element Send Keys](https://w3c.github.io/webdriver/#element-send-keys)\n\nSends keys to the element the identified by `:elementId`. This functionality is only relevant to\nkeyboard-interactable element types, such as input fields.","metadata":{"headerPath":"### getElementRect","sectionCount":13,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### setValue > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`text`|Text to send|string|\n\n### setValue > #### Response\n\n`null`\n\n### getPageSource\n\n```\nGET /session/:sessionId/source\n```\n\n> WebDriver documentation: [Get Page Source](https://w3c.github.io/webdriver/#get-page-source)\n\nRetrieves the page/application source of the current browsing context in HTML/XML format.\n\n### getPageSource > #### Response\n\n`string` - the DOM of the current browsing context\n\n### execute\n\n```\nPOST /session/:sessionId/execute/sync\n```\n\n> WebDriver documentation: [Execute Script](https://w3c.github.io/webdriver/#execute-script)\n\nExecutes synchronous JavaScript code in the current browsing context.\n\n### execute > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`script`|Script function to execute|string|\n|`args`|Arguments passed to the script|array|\n\n### execute > #### Response\n\n`any` - the result of the script execution\n\n### executeAsync\n\n```\nPOST /session/:sessionId/execute/async\n```\n\n> WebDriver documentation: [Execute Async Script](https://w3c.github.io/webdriver/#execute-async-script)\n\nExecutes asynchronous JavaScript code in the current browsing context.\n\nThe `script` function is provided an additional argument (applied after `args`), which is a\nfunction that can be invoked (within `script`) to trigger script completion. The first argument\npassed to this completion function is returned as the endpoint response.\n\n### executeAsync > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`script`|Script function to execute|string|\n|`args`|Arguments for the script|array|\n\n### executeAsync > #### Response\n\n`any` - the result returned by the completion function of the script\n\n### getCookies\n\n```\nGET /session/:sessionId/cookie\n```\n\n> WebDriver documentation: [Get Cookies](https://w3c.github.io/webdriver/#get-cookies)\n\nRetrieves all cookies of the current browsing context.\n\n### getCookies > #### Response\n\n`Cookie[]` - an array containing zero or more [`Cookie` objects](#response_49)\n\n### getCookie\n\n```\nGET /session/:sessionId/cookie/:name\n```\n\n> WebDriver documentation: [Get Named Cookie](https://w3c.github.io/webdriver/#get-named-cookie)\n\nRetrieves a cookie with the name identified by `:name` from the current browsing context.","metadata":{"headerPath":"### setValue > #### Parameters","sectionCount":13,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### getCookie > #### Response\n\n`Cookie` - an object with the following properties:\n\n|Name|Description|Type|\n|--|--|--|\n|`domain?`|Cookie domain|string|\n|`expiry?`|Cookie expiration time (in seconds) as a Unix timestamp|number|\n|`httpOnly?`|Whether the cookie is an HTTP only cookie|boolean|\n|`name`|Cookie name|string|\n|`path?`|Cookie path|string|\n|`sameSite?`|SameSite policy type of the cookie (either `Lax` or `Strict`)|string|\n|`secure?`|Whether the cookie is a secure cookie|boolean|\n|`value`|Cookie value|string|\n\n### setCookie\n\n```\nPOST /session/:sessionId/cookie\n```\n\n> WebDriver documentation: [Add Cookie](https://w3c.github.io/webdriver/#add-cookie)\n\nAdds a cookie to the cookie store of the current browsing context.\n\n### setCookie > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`cookie`|Cookie object to add|[`Cookie`](#response_49)|\n\n### setCookie > #### Response\n\n`null`\n\n### deleteCookie\n\n```\nDELETE /session/:sessionId/cookie/:name\n```\n\n> WebDriver documentation: [Delete Cookie](https://w3c.github.io/webdriver/#delete-cookie)\n\nDeletes a cookie with the name identified by `:name` from the current browsing context.\n\n### deleteCookie > #### Response\n\n`null`\n\n### deleteCookies\n\n```\nDELETE /session/:sessionId/cookie\n```\n\n> WebDriver documentation: [Delete All Cookies](https://w3c.github.io/webdriver/#delete-all-cookies)\n\nDeletes all cookies from the current browsing context.\n\n### deleteCookies > #### Response\n\n`null`\n\n### performActions\n\n```\nPOST /session/:sessionId/actions\n```\n\n> WebDriver documentation: [Perform Actions](https://w3c.github.io/webdriver/#perform-actions)\n\nPerforms a sequence of [actions](https://w3c.github.io/webdriver/#actions).\n\n### performActions > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`actions`|Array of action objects|`ActionSequence[]`|\n\n### performActions > #### Response\n\n`null`\n\n### releaseActions\n\n```\nDELETE /session/:sessionId/actions\n```\n\n> WebDriver documentation: [Release Actions](https://w3c.github.io/webdriver/#release-actions)\n\nReleases all currently depressed keys and pointer buttons.\n\n### releaseActions > #### Response\n\n`null`\n\n### postDismissAlert\n\n```\nPOST /session/:sessionId/alert/dismiss\n```\n\n> WebDriver documentation: [Dismiss Alert](https://w3c.github.io/webdriver/#dismiss-alert)\n\nDismisses the currently displayed user prompt.\n\n### postDismissAlert > #### Response\n\n`null`","metadata":{"headerPath":"### getCookie > #### Response","sectionCount":15,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### postAcceptAlert\n\n```\nPOST /session/:sessionId/alert/accept\n```\n\n> WebDriver documentation: [Accept Alert](https://w3c.github.io/webdriver/#accept-alert)\n\nAccepts the currently displayed user prompt.\n\n### postAcceptAlert > #### Response\n\n`null`\n\n### getAlertText\n\n```\nGET /session/:sessionId/alert/text\n```\n\n> WebDriver documentation: [Get Alert Text](https://w3c.github.io/webdriver/#get-alert-text)\n\nRetrieves the text of the currently displayed user prompt.\n\n### getAlertText > #### Response\n\n`string` - prompt text\n\n### setAlertText\n\n```\nPOST /session/:sessionId/alert/text\n```\n\n> WebDriver documentation: [Send Alert Text](https://w3c.github.io/webdriver/#send-alert-text)\n\nSets the text of the currently displayed user prompt.\n\n### setAlertText > #### Parameters\n\n|Name|Description|Type|\n|--|--|--|\n|`text`|Text to set|string|\n\n### setAlertText > #### Response\n\n`null`\n\n### getScreenshot\n\n```\nGET /session/:sessionId/screenshot\n```\n\n> WebDriver documentation: [Take Screenshot](https://w3c.github.io/webdriver/#take-screenshot)\n\nTakes a screenshot of the current browsing context.\n\n### getScreenshot > #### Response\n\n`string` - a base64-encoded PNG image\n\n### getElementScreenshot\n\n```\nGET /session/:sessionId/element/:elementId/screenshot\n```\n\n> WebDriver documentation: [Take Element Screenshot](https://w3c.github.io/webdriver/#take-element-screenshot)\n\nTakes a screenshot of the visible region encompassed by the bounding rectangle of the element\nidentified by `:elementId`.\n\n### getElementScreenshot > #### Response\n\n`string` - a base64-encoded PNG image\n\n### printPage\n\n```\nPOST /session/:sessionId/print\n```\n\n> WebDriver documentation: [Print Page](https://w3c.github.io/webdriver/#print-page)\n\nPrints the page by rendering it as a paginated PDF document.","metadata":{"headerPath":"### postAcceptAlert","sectionCount":12,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"### printPage > #### Parameters\n\n|<div style=\"width:7em\">Name</div>|Description|<div style=\"width:9em\">Type</div>|Default|\n|--|--|--|--|\n|`orientation?`|Page orientation. Supported values are `portrait` or `landscape`.|string|`portrait`|\n|`scale?`|Page scale. Supported values are in the range `[0.1, 2]`.|number|`1`|\n|`background?`|Whether to include background images|boolean|`false`|\n|`page?`|Object specifying the page width and height|[`PrintPageSize`](#printpagesize)|`{}`|\n|`margin?`|Object specifying the page margins|[`PrintPageMargins`](#printpagemargins)|`{}`|\n|`shrinkToFit?`|Whether to resize page contents to match `PrintPageSize.width`|boolean|`true`|\n|`pageRanges?`|Array of pages to be printed, for example, `[1, 4, '8-9']`|array|`[]`|\n\n### printPage > #### Parameters > ##### `PrintPageSize`\n\n|Name|Description|Type|Default|\n|--|--|--|--|\n|`width?`|Page width. Must be greater than or equal to `(2.54 / 72)`.|number|`21.59`|\n|`height?`|Page height. Must be greater than or equal to `(2.54 / 72)`.|number|`27.94`|\n\n### printPage > #### Parameters > ##### `PrintPageMargins`\n\n|Name|Description|Type|Default|\n|--|--|--|--|\n|`top?`|Page top margin. Must be greater than or equal to `0`.|number|`1`|\n|`bottom?`|Page bottom margin. Must be greater than or equal to `0`.|number|`1`|\n|`left?`|Page left margin. Must be greater than or equal to `0`.|number|`1`|\n|`right?`|Page right margin. Must be greater than or equal to `0`.|number|`1`|\n\n### printPage > #### Response\n\n`string` - a base64-encoded PDF document","metadata":{"headerPath":"### printPage > #### Parameters","sectionCount":4,"filename":"webdriver.md","relativePath":"appium/packages/appium/docs/en/reference/api/webdriver.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Environment Variables\n---\n\nThe primary ways of configuring the Appium server are via [Command-Line Arguments](./server.md) or\nthe [Config File](../../guides/config.md). However, some more advanced features are toggled or\nconfigured via environment variables. To set environment variables, refer to the documentation for\nyour operating system and terminal.\n\nThese are the environment variables that the Appium server understands:\n\n|<div style=\"width:18em\">Variable</div>|Description|\n|--------|-----------|\n|`APPIUM_APPS_CACHE_IGNORE_URL_QUERY`|Set this to a truthy value to remove any query part of a URL when using it as a cache key. See the corresponding [feature request](https://discuss.appium.io/t/regarding-app-caching-when-using-aws-s3-presigned-urls/42713) for more details.|\n|`APPIUM_APPS_CACHE_MAX_AGE`|Set the maximum age (in minutes) for [cached applications](../../guides/caching.md). Do not set it to a lower number than the duration of a single session startup. Default: `60 * 24` (24 hours)|\n|`APPIUM_APPS_CACHE_MAX_ITEMS`|Set the maximum amount of [cached applications](../../guides/caching.md). Do not set it to a lower number than the amount of apps in all parallel sessions per process. Default: `1024`|\n|`APPIUM_HOME`|Set the path to the Appium home directory, which is used for [Managing Extensions](../../guides/managing-exts.md). Default: `.appium` in the home directory of the current user|\n|`APPIUM_OMIT_PEER_DEPS`|Set this to `1` to add `--omit=peer` to all the NPM commands run internally by Appium. Mostly an internal feature.|\n|`APPIUM_RELOAD_EXTENSIONS`|Set this to a truthy value to cause Appium to re-require extensions when new sessions are created. This feature is mostly useful for [building extensions](../../developing/build-drivers.md).|\n|`APPIUM_TMP_DIR`|Set the path to the directory used for temporary files. Same as the `--tmp` command line argument.|\n\nAppium drivers and plugins may define additional environment variables. The following variables are\nused by official plugins:","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"env-vars.md","relativePath":"appium/packages/appium/docs/en/reference/cli/env-vars.md"}},{"pageContent":"Appium drivers and plugins may define additional environment variables. The following variables are\nused by official plugins:\n\n|<div style=\"width:13em\">Variable</div>|Plugin|Description|\n|--------|-----------|-----------|\n|`APPIUM_STORAGE_KEEP_ALL`|`storage`|Set this to `1`, `true` or `yes` to preserve files in the storage after the server process is terminated. By default, stopping the server process also deletes all files in the storage.|\n|`APPIUM_STORAGE_ROOT`|`storage`|Set the path to the directory used for storage. If set to an existing folder, all files in it will be retained after terminating the server, unless specified otherwise using `APPIUM_STORAGE_KEEP_ALL`.|","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"env-vars.md","relativePath":"appium/packages/appium/docs/en/reference/cli/env-vars.md"}},{"pageContent":"---\ntitle: appium driver/plugin\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav {\n display: none;\n }\n</style>\n\nProvides management options for a specific extension (driver or plugin). Both the `appium driver` and\n`appium plugin` subcommands support the same options.\n\nThe following sub-subcommands are supported: `doctor`, `install`, `list`, `run`, `update`,\nand `uninstall`.\n\n## `doctor`\n\nRuns doctor checks for an installed extension, which validate whether the extension has its prerequisites\nconfigured correctly. Note that not all extensions include doctor checks.\n\n!!! note\n\n If you maintain an Appium extension and would like to add Appium Doctor support for it, check\n out the documentation on [Building Doctor Checks](../../developing/build-doctor-checks.md).\n\n## `doctor` > #### Usage\n\n```\nappium {driver|plugin} doctor <extension-name>\n```\n\n|Argument|Description|\n|--|--|\n|`extension-name`|The short name of the installed extension|\n\n## `doctor` > #### Options\n\n|Argument|Description|Type|\n|--|--|--|\n|`--json`|Return the result in JSON format|boolean|\n\n## `doctor` > #### Example\n\n- Run doctor checks for the UiAutomator2 driver:\n\n ```\n appium driver doctor uiautomator2\n ```\n\n## `install`\n\nInstalls an extension.\n\n## `install` > #### Usage\n\n```\nappium {driver|plugin} install <install-spec>\n```\n\n|<div style=\"width:7em\">Argument</div>|Description|\n|--|--|\n|`install-spec`|The short name of an official extension, with optional `npm` version or tag modifier. If using the `--source` option, the expected format of this argument will change ([see below](#source-vs-install-spec)).|\n\n## `install` > #### Options\n\n|Argument|Description|Type|\n|--|--|--|\n|`--json`|Return the result in JSON format|boolean|\n|`--package`|The Node.js package name of the extension. Required if `--source` is set to `git` or `github`.|string|\n|`--source`|The location where Appium should look for the given extension. Supported values are `git`, `github`, `local`, or `npm`. Changes the expected format of `install-spec` ([see below](#source-vs-install-spec)).|string|","metadata":{"headerPath":"","sectionCount":8,"filename":"extensions.md","relativePath":"appium/packages/appium/docs/en/reference/cli/extensions.md"}},{"pageContent":"## `install` > #### Source vs Install Spec\n\n|`source`|Format of `<install-spec>`|\n|--|--|\n|None|The short name of an official extension, with optional modifiers as supported by `npm install` (e.g. version or tag)|\n|`git`|The Git URL of the extension|\n|`github`|The GitHub repository URL of the extension|\n|`local`|The local path to the extension containing its `package.json` file|\n|`npm`|The name of the `npm` package, with optional modifiers as supported by `npm install` (e.g. version or tag)|\n\n## `install` > #### Examples\n\n- Install the latest XCUITest driver:\n\n ```\n appium driver install xcuitest\n ```\n\n- Install the XCUITest driver at version 9.0.0:\n\n ```\n appium driver install xcuitest@9.0.0\n ```\n\n- Install the `beta` version of `@appium/fake-driver` from `npm`:\n\n ```\n appium driver install @appium/fake-driver@beta --source=npm\n ```\n\n- Install a locally-developed plugin:\n\n ```\n appium plugin install /path/to/my/plugin --source=local\n ```\n\n- Install the XCUITest driver from GitHub:\n\n ```\n appium driver install https://github.com/appium/appium-xcuitest-driver --source=github --package=appium-xcuitest-driver\n ```\n\n- Install the XCUITest driver using a Git URL:\n\n ```\n appium driver install git://github.com/appium/appium-xcuitest-driver.git --source=git --package=appium-xcuitest-driver\n ```\n\n## `list`\n\nLists all installed extensions, plus all official extensions that are not installed.\n\n## `list` > #### Usage\n\n```\nappium {driver|plugin} list\n```\n\n## `list` > #### Options\n\n|<div style=\"width:7em\">Argument</div>|Description|Type|\n|--|--|--|\n|`--installed`|Only list all installed extensions|boolean|\n|`--json`|Return the result in JSON format|boolean|\n|`--updates`|List all extensions along with information on whether newer versions are available. Only supported for extensions installed via `npm`.|boolean|\n\n## `list` > #### Example\n\n- List all installed drivers and check if they have newer versions available:\n\n ```\n appium driver list --installed --updates\n ```\n\n## `run`\n\nRuns an extension script, which can assist with setup or perform other tasks. Note that not all\nextensions include scripts.\n\n## `run` > #### Usage\n\n```\nappium {driver|plugin} run <extension-name> <script-name> [script-args]\n```\n\n|Argument|Description|\n|--|--|\n|`extension-name`|The short name of the installed extension|\n|`script-name`|The name of the script to be run|\n|`script-args`|Any additional arguments passed to the script|","metadata":{"headerPath":"## `install` > #### Source vs Install Spec","sectionCount":8,"filename":"extensions.md","relativePath":"appium/packages/appium/docs/en/reference/cli/extensions.md"}},{"pageContent":"## `run` > #### Options\n\n|Argument|Description|Type|\n|--|--|--|\n|`--json`|Return the result in JSON format|boolean|\n\n## `run` > #### Example\n\n- Run the `reset` script included in the UiAutomator2 driver:\n\n ```\n appium driver run uiautomator2 reset\n ```\n\n## `update`\n\nUpdates one or more extensions. Only supported for extensions installed via `npm`. By default,\nAppium will only update minor and patch versions, in order to prevent any breaking changes.\n\n## `update` > #### Usage\n\n```\nappium {driver|plugin} update <extension-name>\n```\n\n|Argument|Description|\n|--|--|\n|`extension-name`|The short name of the installed extension, or `installed` to update all installed extensions|\n\n## `update` > #### Options\n\n|Argument|Description|Type|\n|--|--|--|\n|`--json`|Return the result in JSON format|boolean|\n|`--unsafe`|Allow updates of major versions, which may cause breaking changes|boolean|\n\n## `update` > #### Examples\n\n- Update the UiAutomator2 driver to its latest major version:\n\n ```\n appium driver update uiautomator2 --unsafe\n ```\n\n- Update all installed plugins:\n\n ```\n appium plugin update installed\n ```\n\n## `uninstall`\n\nRemoves an installed extension.\n\n## `uninstall` > #### Usage\n\n```\nappium {driver|plugin} uninstall <extension-name>\n```\n\n|Argument|Description|\n|--|--|\n|`extension-name`|The short name of the installed extension|\n\n## `uninstall` > #### Options\n\n|Argument|Description|Type|\n|--|--|--|\n|`--json`|Return the result in JSON format|boolean|\n\n## `uninstall` > #### Example\n\n- Remove the `images` plugin:\n\n ```\n appium plugin uninstall images\n ```","metadata":{"headerPath":"## `run` > #### Options","sectionCount":10,"filename":"extensions.md","relativePath":"appium/packages/appium/docs/en/reference/cli/extensions.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Command Line Interface\n---\n\nAppium provides a command-line executable (`appium`), which can be used to configure and launch\nthe Appium server, as well as manage Appium extensions (drivers and plugins).\n\nThe executable has four main subcommands: `server`, `driver`, `plugin`, and `setup`. All subcommands\n(and sub-subcommands) can be run with the `--help`/`-h` option for usage instructions.\n\n<div class=\"grid cards\" markdown>\n\n- [__`appium server`__](./server.md) (or simply `appium`)\n\n Start an Appium server\n\n- [__`appium driver`__](./extensions.md)\n\n Manage individual drivers\n\n- [__`appium plugin`__](./extensions.md)\n\n Manage individual plugins\n\n- [__`appium setup`__](./setup.md)\n\n Manage multiple drivers/plugins\n\n</div>\n\nAppium also recognizes several [environment variables](./env-vars.md), which may be used for\nadvanced configuration.","metadata":{"headerPath":"","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/reference/cli/index.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: appium server\n---\n\nLaunches an Appium server.\n\n```\nappium server\n```\n\nYou can also omit the `server` subcommand:\n\n```\nappium\n```","metadata":{"headerPath":"","sectionCount":1,"filename":"server.md","relativePath":"appium/packages/appium/docs/en/reference/cli/server.md"}},{"pageContent":"### Options\n\n!!! note\n\n All of these options can also be set via a [Configuration File](../../guides/config.md). Options\n set on the command line will override any options found in a configuration file.","metadata":{"headerPath":"### Options","sectionCount":1,"recursiveSplit":true,"filename":"server.md","relativePath":"appium/packages/appium/docs/en/reference/cli/server.md"}},{"pageContent":"### Options\n\n|<div style=\"width:15em\">Argument</div>|Description|Type|<div style=\"width:7em\">Default</div>|\n|--|--|--|--|\n|`--address`, `-a`|IPv4/IPv6 address to listen on|string|`0.0.0.0`|\n|`--allow-cors`|Allow web browser connections from any host|boolean|`false`|\n|`--allow-insecure`|List of [insecure features](../../guides/security.md) that should be allowed in this server's sessions. Individual features can be overridden by `--deny-insecure`. Has no effect in combination with `--relaxed-security`.|array<string>|`[]`|\n|`--base-path`, `-pa`|Base path to use as the prefix for all webdriver routes running on the server|string|`\"\"`|\n|`--callback-address`, `-ca`|Callback IP address|string|`0.0.0.0`|\n|`--callback-port`, `-cp`|Callback port|integer|`4723`|\n|`--config`|Path to an [Appium configuration JSON file](../../guides/config.md)|string||\n|`--debug-log-spacing`|Add exaggerated spacing in logs to help with visual inspection|boolean|`false`|\n|`--default-capabilities`, `-dc`|Capabilities that will be used for each session, unless overridden by received capabilities|object||\n|`--deny-insecure`|List of [insecure features](../../guides/security.md) that should be disabled in this server's sessions. Since all insecure features are disabled by default, this argument has no effect without either `--allow-insecure` or `--relaxed-security`, and is applied after both.|array<string>|`[]`|\n|`--driver`|Driver-specific configuration. Keys should correspond to driver package names|object||\n|`--drivers-import-chunk-size`|Maximum number of drivers that can be imported in parallel on server startup|number|`3`|\n|`--keep-alive-timeout`, `-ka`|Timeout (in seconds) to use as both the keep-alive timeout and the connection timeout for all client requests. Disabled if set to `0`.|integer|`600`|\n|`--request-timeout`|Timeout (in seconds) for waiting to receive the entire HTTP request from the client. Disabled if set to `0`. Requests exceeding this timeout will be rejected with the code `HTTP 408`.|integer|`3600`|\n|`--local-timezone`|Use local timezone for log timestamps|boolean|`false`|\n|`--log`, `-g`|Path to a file where the server logs should be output. This does not affect output on the console.|string||\n|`--log-filters`|List of log filtering rules. See the [log filtering guide](../../guides/log-filters.md) for details.|array||","metadata":{"headerPath":"### Options","sectionCount":1,"recursiveSplit":true,"filename":"server.md","relativePath":"appium/packages/appium/docs/en/reference/cli/server.md"}},{"pageContent":"### Options\n\n|`--log-filters`|List of log filtering rules. See the [log filtering guide](../../guides/log-filters.md) for details.|array||\n|`--log-level`|The log level for the server logs. Supported values are `debug`, `info`, `warn`, or `error`. Combining two supported values using a colon (e.g. `warn:debug`) allows to set separate log levels for the console and file outputs, respectively.|string|`debug`|\n|`--log-format`|The log format of the server logs. Supported values are `text`, `json`, or `pretty_json`. Setting the value to `json` disables colors.|string|`text`|\n|`--log-no-colors`|Disable colors in the server log|boolean|`false`|\n|`--log-timestamp`|Show timestamps in the server log|boolean|`false`|\n|`--long-stacktrace`|Add long stack traces to log entries. Recommended for debugging only.|boolean|`false`|\n|`--no-perms-check`|Skip various permission checks on the server startup|boolean|`false`|\n|`--nodeconfig`|JSON configuration for registering Appium as a node with Selenium Grid 3|object||\n|`--plugin`|Plugin-specific configuration. Keys should correspond to plugin package names|object||\n|`--plugins-import-chunk-size`|Maximum number of plugins that can be imported in parallel on server startup|number|`7`|\n|`--port`, `-p`|Port to listen on|integer|`4723`|\n|`--relaxed-security`|Allow all [insecure features](../../guides/security.md). Only use this if all clients are in a trusted network and could not potentially break out of the session sandbox. Specific features can be overridden by using `--deny-insecure`.|boolean|`false`|\n|`--session-override`|Enable session override (clobbering)|boolean|`false`|\n|`--shutdown-timeout`|Timeout (in milliseconds) for waiting on all active connections to close, when shutting down the server|number|`5000`|\n|`--ssl-cert-path`|Absolute path to the `.cert` file if TLS is used. Must be provided together with `--ssl-key-path`. See the [SSL/TLS/SPDY Support guide](../../guides/tls.md) for details.|string||\n|`--ssl-key-path`|Absolute path to the `.key` file if TLS is used. Must be provided together with `--ssl-cert-path`. See the [SSL/TLS/SPDY Support guide](../../guides/tls.md) for details.|string||\n|`--strict-caps`|Prevent creation of new client sessions that use unsupported capabilities|boolean|`false`|\n|`--tmp`|Absolute path to the directory used for temporary files|string|[`os.tmpdir()`](https://nodejs.org/api/os.html#ostmpdir)|","metadata":{"headerPath":"### Options","sectionCount":1,"recursiveSplit":true,"filename":"server.md","relativePath":"appium/packages/appium/docs/en/reference/cli/server.md"}},{"pageContent":"### Options\n\n|`--tmp`|Absolute path to the directory used for temporary files|string|[`os.tmpdir()`](https://nodejs.org/api/os.html#ostmpdir)|\n|`--use-drivers`|List of drivers to activate. By default, all installed drivers are activated.|array<string>|`[]`|\n|`--use-plugins`|List of plugins to activate. By default, no plugins are activated. Set to `[\"all\"]` to activate all installed plugins.|array<string>|`[]`|\n|`--webhook`, `-G`|URL for an HTTP listener where the server logs should be output. This does not affect output on the console.|string||","metadata":{"headerPath":"### Options","sectionCount":1,"recursiveSplit":true,"filename":"server.md","relativePath":"appium/packages/appium/docs/en/reference/cli/server.md"}},{"pageContent":"### Info Options\n\nThe following options are used for reference or debug purposes. They are only supported for the base `appium` command (not `appium server`), and will not launch the server.\n\n|<div style=\"width:10em\">Argument</div>|Description|\n|--|--|\n|`--show-build-info`|Print detailed information on the Appium server version|\n|`--show-config`|Print the current Appium server configuration details|\n|`--show-debug-info`|Print information on the current environment: details about the operating system, Node.js, and Appium itself|\n|`--version`, `-v`|Print the Appium server version|","metadata":{"headerPath":"### Info Options","sectionCount":1,"filename":"server.md","relativePath":"appium/packages/appium/docs/en/reference/cli/server.md"}},{"pageContent":"---\ntitle: appium setup\n---\n<style>\n ul[data-md-component=\"toc\"] .md-nav {\n display: none;\n }\n</style>\n\nInstalls a specific preset of extensions (drivers and plugins), or uninstalls all extensions.\nWhen installing a preset, any already installed extensions are kept intact.\n\nThe following sub-subcommands are supported: `browser`, `desktop`, `mobile`, and `reset`.\n\nRefer to the [Ecosystem documentation](../../ecosystem/index.md) to learn more about the extensions\nmentioned below.\n\n## `browser`\n\nInstalls the following extensions for browser webview testing:\n\n* Drivers: `safari`[^1], `gecko`, `chromium`\n* Plugins: `images`, `inspector`\n\n## `browser` > #### Usage\n\n```\nappium setup browser\n```\n\n## `desktop`\n\nInstalls the following extensions for desktop application testing:\n\n* Drivers: `mac2`[^1], `windows`[^2]\n* Plugins: `images`, `inspector`\n\n## `desktop` > #### Usage\n\n```\nappium setup desktop\n```\n\n## `mobile`\n\nInstalls the following extensions for mobile testing:\n\n* Drivers: `uiautomator2`, `xcuitest`[^1], `espresso`\n* Plugins: `images`, `inspector`\n\n## `mobile` > #### Usage\n\n```\nappium setup mobile\n```\n\nYou can also omit the `mobile` sub-subcommand:\n\n```\nappium setup\n```\n\n## `reset`\n\nUninstalls all installed extensions, along with their manifest files, from the Appium home\ndirectory. This can be useful if you experience configuration issues on server startup, for\nexample, due to a failed upgrade attempt from an older Appium version.\n\n## `reset` > #### Usage\n\n```\nappium setup reset\n```\n\n[^1]: Only installed if the host machine is running macOS.\n[^2]: Only installed if the host machine is running Windows.","metadata":{"headerPath":"","sectionCount":9,"filename":"setup.md","relativePath":"appium/packages/appium/docs/en/reference/cli/setup.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Reference\n---\n\nThis section of the Appium documentation provides a reference to the two main interfaces within the\nAppium server: the command-line executable, and the supported API endpoints.\n\n<div class=\"grid cards\" markdown>\n\n- :octicons-command-palette-16: [__Command Line Interface__](./cli/index.md)\n\n ---\n\n Learn how to use the Appium command-line executable\n\n- :material-cloud-braces: [__API Endpoints__](./api/index.md)\n\n ---\n\n View endpoints supported by the Appium server\n\n</div>","metadata":{"headerPath":"","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/reference/index.md"}},{"pageContent":"---\nhide:\n - navigation\n - toc\n\ntitle: Additional Resources\n---\n\nHere you can find links to additional Appium resources around the web:\n\n## Websites\n\n- [Appium Pro](https://appiumpro.com) - a blog and newsletter written by one of Appium's\nmaintainers, Jonathan Lipps, with lots of useful guides\n\n## Online Courses\n\n- [Appium and Selenium Fundamentals](https://ui.headspin.io/university/learn/appium-selenium-fundamentals-2020) - a comprehensive video course on learning Python, Selenium, and Appium by Jonathan Lipps\n- [Mobile Test Automation with Appium](https://testautomationu.applitools.com/appium-java-tutorial/) - a video course by Moataz Nabil\n- [Advanced Appium](https://www.linkedin.com/learning/advanced-appium) - a video course by Jonathan Lipps\n\n## Conference Archives\n\n- [AppiumConf 2018](https://www.youtube.com/playlist?list=PLhr2WKNPXcZOmOf1k2aqkbMZwnZb2pSZL)\n- [AppiumConf 2019](https://www.youtube.com/playlist?list=PL9Z-JgiTsOYSfJh9YKI9Stj3FMwHERw6w)\n- [AppiumConf 2021](https://www.youtube.com/playlist?list=PL9Z-JgiTsOYRCcJhDfmKAah9XmAp2b903)\n- [AppiumConf 2024](https://www.youtube.com/playlist?list=PL9Z-JgiTsOYQaU5i5LJtAWlh5WVZPi3If)\n- [SeleniumConf & AppiumConf 2025](https://www.youtube.com/playlist?list=PLRdSclUtJDYV2R92TLbmwxws6clruuTjH)","metadata":{"headerPath":"","sectionCount":4,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/resources/index.md"}},{"pageContent":"---\nhide:\n - navigation\n - toc\n\ntitle: Sponsors & Backers\n---\n\n<style>\n .appium-sponsor-thanks { display: none; }\n .sponsor-section img { height: 64px; padding-right: 1em; }\n</style>\n\nAppium is an Apache-2 licensed open source project whose development is made possible entirely by\ndonations of time and money by individuals and companies who benefit from our software and our\nmission. If you'd like to join this amazing group and help ensure Appium's continued development\nand maintenance, you can contribute via [Appium's OpenCollective\nHub](https://opencollective.com/appium).\n\n## Development Partners\n\nWe are very grateful for the support of our Development Partners, who donate Appium development and\nmaintenance as part of their employees' core job duties!\n\n## Strategic Partners\n\nWe are very grateful for the financial and marketing support of our exclusive Strategic Partners,\nwho contribute a significant ongoing investment of funds to help the project attract and reward\ncontributors!\n\n<a href=\"https://www.browserstack.com/browserstack-appium?utm_campaigncode=701OW00000AoUTQYA3&utm_medium=partnered&utm_source=appium\">\n <img src=\"/docs/en/latest/assets/images/sponsor-logo-browserstack-dark.png#only-dark\" width=\"250\" alt=\"BrowserStack\" />\n <img src=\"/docs/en/latest/assets/images/sponsor-logo-browserstack-light.png#only-light\" width=\"250\" alt=\"BrowserStack\" />\n</a>\n\n<a href=\"https://lambdatest.com/?utm_source=appium.io&utm_medium=organic&utm_campaign=june_25&utm_term=sk&utm_content=webpage\">\n <img src=\"/docs/en/latest/assets/images/sponsor-logo-lambdatest-dark.png#only-dark\" width=\"250\" alt=\"LambdaTest\" />\n <img src=\"/docs/en/latest/assets/images/sponsor-logo-lambdatest-light.png#only-light\" width=\"250\" alt=\"LambdaTest\" />\n</a>\n\n## Gold Sponsors\n\n<div class=\"sponsor-section\">\n <a href=\"https://jetify.com/\" target=\"_blank\"><img src=\"https://images.opencollective.com/jetify/415824c/avatar/64.png\" alt=\"Jetify\" /></a>\n</div>\n\n[Become a Gold Sponsor](https://opencollective.com/appium/contribute/gold-sponsor-72877/checkout?interval=month&amount=500&contributeAs=me)\n\n## Silver Sponsors\n\n<div class=\"sponsor-section\">\n <a href=\"https://magicpod.com/\" target=\"_blank\"><img src=\"https://images.opencollective.com/magicpod/722b7e4/avatar/64.png\" alt=\"MagicPod\" /></a>\n</div>\n\n[Become a Silver Sponsor](https://opencollective.com/appium/contribute/silver-sponsor-72876/checkout?interval=month&amount=250&contributeAs=me)","metadata":{"headerPath":"","sectionCount":5,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/sponsors/index.md"}},{"pageContent":"## Bronze Sponsors\n\n<div class=\"sponsor-section\">\n <a href=\"https://route4me.com/\" target=\"_blank\"><img src=\"https://images.opencollective.com/route4me/71fb6fa/avatar/64.png\" alt=\"Route4Me\" /></a>\n <a href=\"https://webdriver.io/\" target=\"_blank\"><img src=\"https://images.opencollective.com/webdriverio/bbdd6c3/avatar/64.png\" alt=\"WebdriverIO\" /></a>\n</div>\n\n[Become a Bronze Sponsor](https://opencollective.com/appium/contribute/sponsors-70690/checkout?interval=month&amount=100&contributeAs=me)","metadata":{"headerPath":"## Bronze Sponsors","sectionCount":1,"filename":"index.md","relativePath":"appium/packages/appium/docs/en/sponsors/index.md"}},{"pageContent":"# appium-manifest types\n\nThis dir contains versioned type declarations for our manifest file (`extensions.yaml`).\n\n# appium-manifest types > ## About\n\nOriginally, the manifest file was versioned; it had a `schemaRev` prop. Eventually, the requirement for this prop was dropped, and became optional. As of this writing, it is now required again. \n\nThe idea was that if Appium found an `extensions.yaml` with a `schemaRev` lower than its \"current\" revision, it would \"migrate\" the file to the current revision. When we removed the requirement for the `schemaRev` prop, we removed this logic.\n\nAs of _v3_ of the schema, we are reinstating versioning and migrations.","metadata":{"headerPath":"# appium-manifest types","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/appium/types/manifest/README.md"}},{"pageContent":"# appium-manifest types > ## How To Add A New Version\n\nThe manifest file types—and thus its format—is composed of types used elsewhere in our codebase. This is probably a design flaw, but the fact remains that the manifest file's format is strongly coupled to Appium's extension-handling logic.\n\nFor that reason, it is _non-trivial_ to reuse the types declared by older revisions to declare a new revision. If and when someone de-couples the types from the schema, we will have to use the _copy-and-paste_ strategy to create a new version.\n\n1. The current version of the schema is defined in `constants.js` as `CURRENT_SCHEMA_REV`. **Increment** this value.\n2. **Copy** the `.ts` file in this directory corresponding to the (now old) current version of the schema into a new file named `v<new-version>.ts`. For example, if the current version is `3`, and you're creating `4`, then you would copy `v3.ts` to `v4.ts`.\n3. **Modify** your new file to do whatever it is you need to do with it. Do _not_ build types upon old versions of the schema.\n4. **Modify** `index.ts`:\n 1. **Append** `import * as ManifestV<new-version> from './v<new-version>'`\n 2. **Replace** `export * from './v<current-version>'` with `export * from './v<new-version>'`\n 3. **Append** `ManifestV<new-version>` to the `export {ManifestV...}` line.\n 4. **Append** a key/value pair to `ManifestDataVersions` with the new _numeric_ version number as the key and the value `ManifestV<new-version>.ManifestData`.\n5. **Create** a new `const SCHEMA_REV_<new-version> = <new-version>` in `manifest-migrations.js`.\n6. Finally, **append** a new key/value pair to the `Migrations` object in `manifest-migrations.js`. The key should be a reference to the constant created in step 5, and the value should be a function which performs the migration from the (old) current version to the new version.\n\n-- @boneskull, Nov 8 2022","metadata":{"headerPath":"# appium-manifest types > ## How To Add A New Version","sectionCount":1,"filename":"README.md","relativePath":"appium/packages/appium/types/manifest/README.md"}},{"pageContent":"# @appium/base-driver\n\n> Base class for creating other Appium drivers\n\n[![NPM version](http://img.shields.io/npm/v/@appium/base-driver.svg)](https://npmjs.org/package/@appium/base-driver)\n[![Downloads](http://img.shields.io/npm/dm/@appium/base-driver.svg)](https://npmjs.org/package/@appium/base-driver)\n\nThis is the parent class that all Appium drivers inherit from. This driver should not be installed\ndirectly as it does nothing on its own. Instead, you should extend this driver when creating your\n*own* Appium drivers. Check out the [Building Drivers](https://appium.io/docs/en/latest/developing/build-drivers/)\ndocumentation for more details.\n\n# @appium/base-driver > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/base-driver","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/base-driver/README.md"}},{"pageContent":"## Mobile JSON Wire Protocol Errors\n\nThis package exports a number of classes and methods related to Selenium error handling. There are error classes for each Selenium error type (see [here](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Response_Status_Codes), as well as the context errors in the [mobile spec](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md#webviews-and-other-contexts)).\n\nThese classes, which are constructed with a string message (defaulting to the \"Details\" below), are available through the `errors` object exported by the module. They are","metadata":{"headerPath":"## Mobile JSON Wire Protocol Errors","sectionCount":1,"recursiveSplit":true,"filename":"errors.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/errors.md"}},{"pageContent":"## Mobile JSON Wire Protocol Errors\n\n| Code | Class Name | Details\n| -----|----------------------------------|-----------------------------------------------\n| | `MJSONWPError`<sup>1</sup> | Base class for other errors\n| 6 | `NoSuchDriverError` | A session is either terminated or not started\n| 7 | `NoSuchElementError` | An element could not be located on the page using the given search parameters\n| 8 | `NoSuchFrameError` | A request to switch to a frame could not be satisfied because the frame could not be found\n| 9 | `UnknownCommandError` | The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource\n| 10 | `StaleElementReferenceError` | An element command failed because the referenced element is no longer attached to the DOM\n| 11 | `ElementNotVisibleError` | An element command could not be completed because the element is not visible on the page\n| 12 | `InvalidElementStateError` | An element command could not be completed because the element is in an invalid state (e.g., attempting to click a disabled element)\n| 13 | `UnknownError` | An unknown server-side error occurred while processing the command\n| 405 | `NotYetImplementedError` | The operation requested is not yet implemented by the driver\n| 405 | `NotImplementedError` | The operation requested will not be implemented by the driver\n| 15 | `ElementIsNotSelectableError` | An attempt was made to select an element that cannot be selected\n| 17 | `JavaScriptError` | An error occurred while executing user supplied JavaScript\n| 19 | `XPathLookupError` | An error occurred while searching for an element by XPath\n| 21 | `TimeoutError` | An operation did not complete before its timeout expired\n| 23 | `NoSuchWindowError` | A request to switch to a different window could not be satisfied because the window could not be found\n| 24 | `InvalidCookieDomainError` | An illegal attempt was made to set a cookie under a different domain than the current page\n| 25 | `UnableToSetCookieError` | A request to set a cookie's value could not be satisfied\n| 26 | `UnexpectedAlertOpenError` | A modal dialog was open, blocking this operation","metadata":{"headerPath":"## Mobile JSON Wire Protocol Errors","sectionCount":1,"recursiveSplit":true,"filename":"errors.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/errors.md"}},{"pageContent":"## Mobile JSON Wire Protocol Errors\n\n| 25 | `UnableToSetCookieError` | A request to set a cookie's value could not be satisfied\n| 26 | `UnexpectedAlertOpenError` | A modal dialog was open, blocking this operation\n| 27 | `NoAlertOpenError` | An attempt was made to operate on a modal dialog when one was not open\n| 28 | `ScriptTimeoutError` | A script did not complete before its timeout expired\n| 29 | `InvalidElementCoordinatesError` | The coordinates provided to an interactions operation are invalid\n| 30 | `IMENotAvailableError` | Input Method Editor was not available\n| 31 | `IMEEngineActivationFailedError` | An Input Method Editor engine could not be started\n| 32 | `InvalidSelectorError` | Argument was an invalid selector (e.g., XPath/CSS)\n| 33 | `SessionNotCreatedError` | A new session could not be created\n| 34 | `MoveTargetOutOfBoundsError` | Target provided for a move action is out of bounds\n| 35 | `NoSuchContextError` | Context provided (e.g., `WEBVIEW_42`) does not exist\n| 36 | `InvalidContextError` | The operation could not be performed in the current context\n| | |\n| | `BadParametersError`<sup>2</sup> | The parameters specified for the operation are incorrect","metadata":{"headerPath":"## Mobile JSON Wire Protocol Errors","sectionCount":1,"recursiveSplit":true,"filename":"errors.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/errors.md"}},{"pageContent":"## Mobile JSON Wire Protocol Errors\n\n<sup>1</sup> `MJSONWPError` is the base class for all errors that are part of the Selenium specification (i.e., all errors except `BadParametersError`), and not itself part of that specification.\n<sup>2</sup> `BadParametersError` is not part of the Selenium specification, but deals with request management.\n\nThere are, in addition, two helper methods for dealing with errors\n\n`isErrorType (err, type)`\n\n- checks if the `err` object is a Mobile JSON Wire Protocol error of a particular type\n- arguments\n - `err` - the error object to test\n - `type` - the error class to test against\n- usage\n ```js\n import { errors, isErrorType } from 'appium-base-driver';\n\n try {\n // do some stuff...\n } catch (err) {\n if (isErrorType(err, errors.InvalidCookieDomainError)) {\n // process...\n }\n }\n ```\n\n`errorFromCode (code, message)`\n\n- retrieve the appropriate error for an error code, with the supplied message.\n- arguments\n - `code` - the integer error code for a Mobile JSON Wire Protocol error\n - `message` - the message to be encapsulated in the error\n- usage\n ```js\n import { errors, errorFromCode } from 'appium-base-driver';\n\n let error = errorFromCode(6, 'an error has occurred');\n\n console.log(error instanceof errors.NoSuchDriverError);\n // => true\n\n console.log(error.message === 'an error has occurred');\n // => true\n ```","metadata":{"headerPath":"## Mobile JSON Wire Protocol Errors","sectionCount":1,"recursiveSplit":true,"filename":"errors.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/errors.md"}},{"pageContent":"## Currently supported endpoints\n\nThe following are endpoints that are currently supported by the Appium server. Particular drivers may or may not implement functionality depending on the underlying system.","metadata":{"headerPath":"## Currently supported endpoints","sectionCount":1,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### WebDriver endpoints\n\nSee the WebDriver [W3C](https://w3c.github.io/webdriver/webdriver-spec.html#list-of-endpoints) and [JSON Wire Protocol](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol) specifications.","metadata":{"headerPath":"## Currently supported endpoints > ### WebDriver endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### WebDriver endpoints\n\nHTTP Method | Path | Details\n------------|------------------------------------------------------------------------|---------\nGET | `status` | Retrieve the server’s current status.\nPOST | `session` | Create a new session.\nGET | `sessions` | Retrieve a list of currently active sessions.\nGET | `session/{sessionId}` | Retrieve the capabilities of the specified session.\nDELETE | `session/{sessionId}` | Delete the session.\nPOST | `session/{sessionId}/timeouts` | Configure the amount of time that a particular type of operation can execute for before they are aborted and a |Timeout| error is returned to the client.\nPOST | `session/{sessionId}/timeouts/async_script` | Set the amount of time that asynchronous scripts executed by `/session/{sessionId/execute_async` are permitted to run before they are aborted.\nPOST | `session/{sessionId}/timeouts/implicit_wait` | Set the amount of time the driver should wait when searching for elements.\nGET | `session/{sessionId}/window_handle` | Retrieve the current window handle.\nGET | `session/{sessionId}/window_handles` | Retrieve the list of all window handles available to the session.\nGET | `session/{sessionId}/url` | Retrieve the URL of the current page.\nPOST | `session/{sessionId}/url` | Navigate to a new URL.\nPOST | `session/{sessionId}/forward` | Navigate forwards in the browser history, if possible.\nPOST | `session/{sessionId}/back` | Navigate backwards in the browser history, if possible.\nPOST | `session/{sessionId}/refresh` | Refresh the current page.\nPOST | `session/{sessionId}/execute` | Inject a snippet of JavaScript into the page for execution in the current context.","metadata":{"headerPath":"## Currently supported endpoints > ### WebDriver endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### WebDriver endpoints\n\nPOST | `session/{sessionId}/execute` | Inject a snippet of JavaScript into the page for execution in the current context.\nPOST | `session/{sessionId}/execute_async` | Inject a snippet of JavaScript into the page for asynchronous execution in the context of the currently selected frame.\nGET | `session/{sessionId}/screenshot` | Take a screenshot of the current page.\nGET | `session/{sessionId}/ime/available_engines` | List all available input engines on the machine.\nGET | `session/{sessionId}/ime/active_engine` | Get the name of the active IME engine.\nGET | `session/{sessionId}/ime/activated` | Indicates whether IME input is active at the moment (not if it is available).\nPOST | `session/{sessionId}/ime/deactivate` | De-activates the currently-active IME engine.\nPOST | `session/{sessionId}/ime/activate` | Make an engine that is available active.\nPOST | `session/{sessionId}/frame` | Change focus to another frame on the page.\nPOST | `session/{sessionId}/window` | Change focus to another window.\nGET | `session/{sessionId}/window/{windowhandle}/size` | Get the size of the specified window.\nPOST | `session/{sessionId}/window/{windowhandle}/maximize` | Maximize the specified window if not already maximized.\nGET | `session/{sessionId}/cookie` | Retrieve all cookies visible to the current page.\nPOST | `session/{sessionId}/cookie` | Set a cookie.\nDELETE | `session/{sessionId}/cookie` | Delete all cookies visible to the current page.\nDELETE | `session/{sessionId}/cookie/{name}` | Delete the cookie with the given name.\nGET | `session/{sessionId}/source` | Get the current page source.\nGET | `session/{sessionId}/title` | Get the current page title.\nPOST | `session/{sessionId}/element` | Search for an element on the page, starting from the document root.","metadata":{"headerPath":"## Currently supported endpoints > ### WebDriver endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### WebDriver endpoints\n\nPOST | `session/{sessionId}/element` | Search for an element on the page, starting from the document root.\nPOST | `session/{sessionId}/elements` | Search for multiple elements on the page, starting from the document root.\nPOST | `session/{sessionId}/element/active` | Get the element on the page that currently has focus.\nPOST | `session/{sessionId}/element/{elementId}/element` | Search for an element on the page, starting from the identified element.\nPOST | `session/{sessionId}/element/{elementId}/elements` | Search for multiple elements on the page, starting from the identified element.\nPOST | `session/{sessionId}/element/{elementId}/click` | Click on an element.\nPOST | `session/{sessionId}/element/{elementId}/submit` | Submit a form element.\nGET | `session/{sessionId}/element/{elementId}/text` | Returns the visible text for the element.\nPOST | `session/{sessionId}/element/{elementId}/value` | Send a sequence of key strokes to an element.\nPOST | `session/{sessionId}/keys` | Send a sequence of key strokes to the active element.\nGET | `session/{sessionId}/element/{elementId}/name` | Query for an element's tag name.\nPOST | `session/{sessionId}/element/{elementId}/clear` | Clear a text element's value.\nGET | `session/{sessionId}/element/{elementId}/selected` | Determine if an element is currently selected.\nGET | `session/{sessionId}/element/{elementId}/enabled` | Determine if an element is currently enabled.\nGET | `session/{sessionId}/element/{elementId}/attribute/{name}` | Get the value of an element's attribute.\nGET | `session/{sessionId}/element/{elementId}/equals/{otherId}` | Test if two element IDs refer to the same element.\nGET | `session/{sessionId}/element/{elementId}/displayed` | Determine if an element is currently displayed.\nGET | `session/{sessionId}/element/{elementId}/location` | Determine an element's location on the page.\nGET | `session/{sessionId}/element/{elementId}/location_in_view` | Determine an element's location on the screen once it has been scrolled into view.","metadata":{"headerPath":"## Currently supported endpoints > ### WebDriver endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### WebDriver endpoints\n\nGET | `session/{sessionId}/element/{elementId}/location_in_view` | Determine an element's location on the screen once it has been scrolled into view.\nGET | `session/{sessionId}/element/{elementId}/size` | Determine an element's size in pixels.\nGET | `session/{sessionId}/element/{elementId}/css/{propertyName}` | Query the value of an element's computed CSS property.\nGET | `session/{sessionId}/orientation` | Get the current device orientation.\nPOST | `session/{sessionId}/orientation` | Set the device orientation\nGET | `session/{sessionId}/alert_text` | Gets the text of the currently displayed dialog\nPOST | `session/{sessionId}/alert_text` | Sends keystrokes to the currently displayed dialog\nPOST | `session/{sessionId}/accept_alert` | Accepts the currently displayed alert dialog.\nPOST | `session/{sessionId}/dismiss_alert` | Dismisses the currently displayed alert dialog.\nPOST | `session/{sessionId}/moveto` | Move the pointer by an offset of the specified element.\nPOST | `session/{sessionId}/click` | Click on the current pointer position.\nPOST | `session/{sessionId}/touch/click` | Single tap on the touch enabled device.\nPOST | `session/{sessionId}/touch/down` | Finger down on the screen.\nPOST | `session/{sessionId}/touch/up` | Finger up on the screen.\nPOST | `session/{sessionId}/touch/move` | Finger move on the screen.\nPOST | `session/{sessionId}/touch/longclick` | Long press on the touch screen using finger motion events.\nPOST | `session/{sessionId}/touch/flick` | Flick on the touch screen using finger motion events.\nGET | `session/{sessionId}/location` | Get the current geo location.\nPOST | `session/{sessionId}/location` | Set the current geo location.\nPOST | `session/{sessionId}/log` | Get the log for a given log type.","metadata":{"headerPath":"## Currently supported endpoints > ### WebDriver endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### WebDriver endpoints\n\nPOST | `session/{sessionId}/log` | Get the log for a given log type.\nGET | `session/{sessionId}/log/types` | Get available log types.","metadata":{"headerPath":"## Currently supported endpoints > ### WebDriver endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### Mobile JSON Wire Protocol endpoints\n\nSee https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md\n\nHTTP Method | Path | Details\n------------|------------------------------------------------------------------------|---------\nGET | `session/{sessionId}/context` | Retrieves the current context.\nPOST | `session/{sessionId}/context` | Switches to the given context.\nGET | `session/{sessionId}/contexts` | Retrieves an array of strings representing available contexts.\nGET | `session/{sessionId}/element/{elementId}/pageIndex` |\nGET | `session/{sessionId}/network_connection` | Retrieves the current network connection type.\nPOST | `session/{sessionId}/network_connection` | Sets the network connection to the given type.\nPOST | `session/{sessionId}/touch/perform` | Perform the given touch action sequence.\nPOST | `session/{sessionId}/touch/multi/perform` | Perform the given multi-touch action sequence.\nPOST | `session/{sessionId}/receive_async_response` | Callback url for asynchronous execution of JavaScript.","metadata":{"headerPath":"## Currently supported endpoints > ### Mobile JSON Wire Protocol endpoints","sectionCount":1,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### Appium extension endpoints\n\nSee https://w3c.github.io/webdriver/webdriver-spec.html#protocol-extensions","metadata":{"headerPath":"## Currently supported endpoints > ### Appium extension endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### Appium extension endpoints\n\nHTTP Method | Path | Details\n------------|------------------------------------------------------------------------|---------\nPOST | `session/{sessionId}/appium/device/shake` | Perform a shake action on the device.\nPOST | `session/{sessionId}/appium/device/lock` | Lock the device.\nPOST | `session/{sessionId}/appium/device/unlock` | Unlock the device.\nPOST | `session/{sessionId}/appium/device/is_locked` | Check whether the device is locked or not.\nPOST | `session/{sessionId}/appium/start_recording_screen` | start recording the screen.\nPOST | `session/{sessionId}/appium/stop_recording_screen` | stop recording the screen.\nPOST | `session/{sessionId}/appium/performanceData/types` | returns the information types of the system state which is supported to read as like cpu, memory, network traffic, and battery.\nPOST | `session/{sessionId}/appium/getPerformanceData` | returns the information of the system state which is supported to read as like cpu, memory, network traffic, and battery.\nPOST | `session/{sessionId}/appium/device/press_keycode` | Press a particular key code on the device.\nPOST | `session/{sessionId}/appium/device/long_press_keycode` | Press and hold a particular key code on the device.\nPOST | `session/{sessionId}/appium/device/keyevent` | Send a key code to the device.\nGET | `session/{sessionId}/appium/device/current_activity` | Retrieve the current activity running on the device.\nGET | `session/{sessionId}/appium/device/current_package` | Retrieve the current package running on the device.\nPOST | `session/{sessionId}/appium/device/install_app` | Install the given app onto the device.\nPOST | `session/{sessionId}/appium/device/remove_app` | Remove an app from the device.\nPOST | `session/{sessionId}/appium/device/app_installed` | Check whether the specified app is installed on the device.\nPOST | `session/{sessionId}/appium/device/hide_keyboard` | Hide the soft keyboard.\nGET | `session/{sessionId}/appium/device/is_keyboard_shown` | Whether or not the soft keyboard is shown.","metadata":{"headerPath":"## Currently supported endpoints > ### Appium extension endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### Appium extension endpoints\n\nGET | `session/{sessionId}/appium/device/is_keyboard_shown` | Whether or not the soft keyboard is shown.\nPOST | `session/{sessionId}/appium/device/push_file` | Place a file onto the device in a particular place.\nPOST | `session/{sessionId}/appium/device/pull_file` | Retrieve a file from the device's file system.\nPOST | `session/{sessionId}/appium/device/pull_folder` | Retrieve a folder from the device's file system.\nPOST | `session/{sessionId}/appium/device/toggle_airplane_mode` | Switch the state of airplane mode.\nPOST | `session/{sessionId}/appium/device/toggle_data` | Switch the state of data service.\nPOST | `session/{sessionId}/appium/device/toggle_wifi` | Switch the state of the wifi service.\nPOST | `session/{sessionId}/appium/device/toggle_location_services` | Switch the state of the location service.\nPOST | `session/{sessionId}/appium/device/open_notifications` | Open the notifications pane on the device.\nPOST | `session/{sessionId}/appium/device/start_activity` | Start the specified activity on the device.\nGET | `session/{sessionId}/appium/device/system_bars` | Retrieve visibility and bounds information of the status and navigation bars.\nGET | `session/{sessionId}/appium/device/display_density` | Retrieve the display density of the device.\nPOST | `session/{sessionId}/appium/simulator/toggle_touch_id_enrollment` | Toggle enrollment of touch id on the simulator.\nPOST | `session/{sessionId}/appium/simulator/touch_id` | Simulate a successful or failed touch id event on the simulator.\nPOST | `session/{sessionId}/appium/app/launch` | Launch the given application on the device.\nPOST | `session/{sessionId}/appium/app/close` | Close the given application.\nPOST | `session/{sessionId}/appium/app/reset` | Reset the device.\nPOST | `session/{sessionId}/appium/app/background` | Send the current application to the background.\nPOST | `session/{sessionId}/appium/app/end_test_coverage` | End test coverage on the device.\nPOST | `session/{sessionId}/appium/app/strings` | Retrieve the application's strings file.","metadata":{"headerPath":"## Currently supported endpoints > ### Appium extension endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### Appium extension endpoints\n\nPOST | `session/{sessionId}/appium/app/strings` | Retrieve the application's strings file.\nPOST | `session/{sessionId}/appium/element/{elementId}/value` | Retrieve the value from the given element.\nPOST | `session/{sessionId}/appium/element/{elementId}/replace_value` | Replace the value of the given element.\nGET | `session/{sessionId}/appium/settings` | Retrieve a JSON hash of all the currently specified settings.\nPOST | `session/{sessionId}/appium/settings` | Update the current setting on the device.\nPOST | `session/{sessionId}/appium/receive_async_response` | Callback url for asynchronous execution of JavaScript.","metadata":{"headerPath":"## Currently supported endpoints > ### Appium extension endpoints","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### Not implemented\n\nThe following routes are not implemented by any Appium driver, and will throw an error.","metadata":{"headerPath":"## Currently supported endpoints > ### Not implemented","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### Not implemented\n\nHTTP Method | Path | Details\n------------|------------------------------------------------------------------------|---------\nPOST | `session/{sessionId}/frame/parent` | Change focus to the parent frame.\nPOST | `session/{sessionId}/window/{windowhandle}/size` | Change the size of the specified window.\nGET | `session/{sessionId}/window/{windowhandle}/position` | Get the position of the specified window.\nPOST | `session/{sessionId}/window/{windowhandle}/position` | Change the position of the specified window.\nGET | `session/{sessionId}/element/{elementId}` | Describe the identified element.\nPOST | `session/{sessionId}/buttondown` | Click and hold the left mouse button (at the coordinates set by the last moveto command).\nPOST | `session/{sessionId}/buttonup` | Releases the mouse button previously held (where the mouse is currently at).\nPOST | `session/{sessionId}/doubleclick` | Double-clicks at the current mouse coordinates (set by moveto).\nPOST | `session/{sessionId}/touch/scroll` | Scroll on the touch screen using finger based motion events.\nPOST | `session/{sessionId}/touch/doubleclick` | Double tap on the touch screen using finger motion events.\nGET | `session/{sessionId}/local_storage` | Get all keys of the storage.\nPOST | `session/{sessionId}/local_storage` | Set the storage item for the given key.\nDELETE | `session/{sessionId}/local_storage` | Clear the storage.\nGET | `session/{sessionId}/local_storage/key/{key}` | Get the storage item for the given key.\nDELETE | `session/{sessionId}/local_storage/key/{key}` | Remove the storage item for the given key.\nGET | `session/{sessionId}/local_storage/size` | Get the number of items in the storage.\nGET | `session/{sessionId}/session_storage` | Get all keys of the storage.\nPOST | `session/{sessionId}/session_storage` | Set the storage item for the given key.","metadata":{"headerPath":"## Currently supported endpoints > ### Not implemented","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"## Currently supported endpoints > ### Not implemented\n\nPOST | `session/{sessionId}/session_storage` | Set the storage item for the given key.\nDELETE | `session/{sessionId}/session_storage` | Clear the storage.\nGET | `session/{sessionId}/session_storage/key/{key}` | Get the storage item for the given key.\nDELETE | `session/{sessionId}/session_storage/key/{key}` | Remove the storage item for the given key.\nGET | `session/{sessionId}/session_storage/size` | Get the number of items in the storage.\nGET | `session/{sessionId}/application_cache/status` | Get the status of the html5 application cache.","metadata":{"headerPath":"## Currently supported endpoints > ### Not implemented","sectionCount":1,"recursiveSplit":true,"filename":"protocol-methods.md","relativePath":"appium/packages/base-driver/docs/mjsonwp/protocol-methods.md"}},{"pageContent":"# @appium/base-plugin\n\n> Base class for creating other Appium plugins\n\n[![NPM version](http://img.shields.io/npm/v/@appium/base-plugin.svg)](https://npmjs.org/package/@appium/base-plugin)\n[![Downloads](http://img.shields.io/npm/dm/@appium/base-plugin.svg)](https://npmjs.org/package/@appium/base-plugin)\n\nThis is the parent class that all Appium plugins inherit from. This plugin should not be installed\ndirectly as it does nothing on its own. Instead, you should extend this plugin when creating your\n*own* Appium plugins. Check out the [Building Plugins](https://appium.io/docs/en/latest/developing/build-plugins/)\ndocumentation for more details.\n\n# @appium/base-plugin > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/base-plugin","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/base-plugin/README.md"}},{"pageContent":"# @appium/docutils\n\n> Documentation-building utilities for Appium\n\n[![NPM version](http://img.shields.io/npm/v/@appium/docutils.svg)](https://npmjs.org/package/@appium/docutils)\n[![Downloads](http://img.shields.io/npm/dm/@appium/docutils.svg)](https://npmjs.org/package/@appium/docutils)\n\n# @appium/docutils > ## Setup for Main Appium Docs\n\nThis package does not need to be run directly. Instead, execute this command in the\n`packages/appium` directory:\n\n```bash\nnpm run dev:docs:en\n```\n\n> [!NOTE]\n> This will only build the English docs. See the `scripts` field of the `package.json` for\nother languages.\n\n# @appium/docutils > ## Setup for Appium Drivers and Plugins\n\nSee the Appium docs on [Building Documentation](http://appium.io/docs/en/latest/developing/build-docs/).\n\n# @appium/docutils > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/docutils","sectionCount":4,"filename":"README.md","relativePath":"appium/packages/docutils/README.md"}},{"pageContent":"# @appium/driver-test-support\n\n> Testing utilities for [Appium](https://appium.io) drivers\n\nThis package is for driver authors to help test their drivers.\n\n[Mocha](https://mochajs.org) is the supported test framework.\n\n# @appium/driver-test-support > ## Usage\n\n# @appium/driver-test-support > ## Usage > ### For E2E Tests\n\nThe `driverE2ETestSuite` method creates a Mocha test suite which makes HTTP requests to an in-memory server leveraging your driver.\n\nNote that this method must be run within a _suite callback_—not a _test callback_.\n\n```js\nimport {driverE2ETestSuite} from '@appium/driver-test-support';\n\nconst defaultW3CCapabilities = {\n // some capabilities\n};\n\ndescribe('MyDriverClass', function() {\n driverE2ETestSuite(MyDriverClass, defaultW3CCapabilities);\n\n describe('more tests', function() {\n // ...\n });\n});\n```\n\n# @appium/driver-test-support > ## Usage > ### For Unit Tests\n\nThe `driverUnitTestSuite` method creates a Mocha test suite which performs assertions on an isolated instance of your driver.\n\nNote that this method must be run within a _suite callback_—not a _test callback_.\n\n```js\nimport {driverUnitTestSuite} from '@appium/driver-test-support';\n\nconst defaultW3CCapabilities = {\n // some capabilities\n};\n\ndescribe('MyDriverClass', function() {\n driverUnitTestSuite(MyDriverClass, defaultW3CCapabilities);\n\n describe('more tests', function() {\n // ...\n });\n});\n```","metadata":{"headerPath":"# @appium/driver-test-support","sectionCount":4,"filename":"README.md","relativePath":"appium/packages/driver-test-support/README.md"}},{"pageContent":"# @appium/driver-test-support > ## Usage > ### Helpers\n\nThese are just some helpers (mainly for E2E tests):\n\n```js\nimport {TEST_HOST, getTestPort, createAppiumURL} from '@appium/driver-test-support';\nimport assert from 'node:assert';\nimport _ from 'lodash';\n\ndescribe('TEST_HOST', function() {\n it('should be localhost', function() {\n assert.strictEqual(TEST_HOST, '127.0.0.1');\n });\n});\n\ndescribe('getTestPort()', function() {\n it('should get a free test port', async function() {\n const port = await getTestPort();\n assert.ok(port > 0);\n });\n});\n\ndescribe('createAppiumURL()', function() {\n it('should create a \"new session\" URL', function() {\n const actual = createAppiumURL(TEST_HOST, 31337, '', 'session');\n const expected = `http://${TEST_HOST}:31337/session`;\n assert.strictEqual(actual, expected);\n });\n \n it('should create a URL to get an existing session', function() {\n const sessionId = '12345';\n const createGetSessionURL = createAppiumURL(TEST_HOST, 31337, _, 'session');\n const actual = createGetSessionURL(sessionId);\n const expected = `http://${TEST_HOST}:31337/session/${sessionId}/session`;\n assert.strictEqual(actual, expected);\n });\n \n it('should create a URL for a command using an existing session', function() {\n const sessionId = '12345';\n const createURLWithPath = createAppiumURL('127.0.0.1', 31337, sessionId);\n const actual = createURLWithPath('moocow');\n const expected = `http://${TEST_HOST}:31337/session/${sessionId}/moocow`;\n assert.strictEqual(actual, expected);\n });\n});\n```\n\n# @appium/driver-test-support > ## Installation\n\n`appium` and `mocha` are peer dependencies.\n\n```bash\nnpm install appium mocha @appium/driver-test-support --save-dev\n```\n\n# @appium/driver-test-support > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/driver-test-support > ## Usage > ### Helpers","sectionCount":3,"filename":"README.md","relativePath":"appium/packages/driver-test-support/README.md"}},{"pageContent":"# @appium/eslint-config-appium-ts\n\n> Provides a reusable [ESLint](http://eslint.org/) [shared configuration](http://eslint.org/docs/developer-guide/shareable-configs) for [Appium](https://github.com/appium/appium) and Appium-adjacent projects.\n\n[![NPM version](http://img.shields.io/npm/v/@appium/eslint-config-appium-ts.svg)](https://npmjs.org/package/@appium/eslint-config-appium-ts)\n[![Downloads](http://img.shields.io/npm/dm/@appium/eslint-config-appium-ts.svg)](https://npmjs.org/package/@appium/eslint-config-appium-ts)\n\n# @appium/eslint-config-appium-ts > ## Usage\n\nInstall the package:\n\n```bash\nnpm install @appium/eslint-config-appium-ts --save-dev\n```\n\nAnd then, in your `eslint.config.mjs` file, extend the configuration:\n\n```js\nimport appiumConfig from '@appium/eslint-config-appium-ts';\n\nexport default [\n ...appiumConfig,\n // add any other config changes \n];\n```\n\n# @appium/eslint-config-appium-ts > ## Notes\n\n- This configuration is intended to be used alongside [Prettier](https://www.npmjs.com/package/prettier).\n\n# @appium/eslint-config-appium-ts > ## License\n\nCopyright © 2023 OpenJS Foundation. Licensed Apache-2.0","metadata":{"headerPath":"# @appium/eslint-config-appium-ts","sectionCount":4,"filename":"README.md","relativePath":"appium/packages/eslint-config-appium-ts/README.md"}},{"pageContent":"# @appium/execute-driver-plugin\n\n> Appium plugin for running a driver script in a child process\n\n[![NPM version](http://img.shields.io/npm/v/@appium/execute-driver-plugin.svg)](https://npmjs.org/package/@appium/execute-driver-plugin)\n[![Downloads](http://img.shields.io/npm/dm/@appium/execute-driver-plugin.svg)](https://npmjs.org/package/@appium/execute-driver-plugin)\n\nThis plugin adds a new driver command that allows executing scripts in a child process. Currently,\nthe only supported driver type is `webdriverio`, therefore the script must also be written in JS.\n\n# @appium/execute-driver-plugin > ## Motivation\n\nRunning a driver script in a child process adds a degree of parallelisation, which may result in\nfaster test execution.\n\n# @appium/execute-driver-plugin > ## Installation\n\n```\nappium plugin install execute-driver\n```\n\nThe plugin must be explicitly activated when launching the Appium server. Since the input script\ncan be arbitrary JavaScript, this is an insecure feature, and must also be explicitly enabled:\n\n```\nappium --use-plugins=execute-driver --allow-insecure=execute_driver_script\n```\n\n# @appium/execute-driver-plugin > ## Usage\n\n```js\nconst script = `return await driver.getTimeouts();`;\nconst {result, logs} = await driver.executeDriverScript(script);\n// 'result' contains the data returned by the script (in this case, the response to 'getTimeouts')\n// 'logs' contains everything logged to console during script execution\n```\n\nRefer to your Appium client documentation for the exact syntax of this command.\n\n# @appium/execute-driver-plugin > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/execute-driver-plugin","sectionCount":5,"filename":"README.md","relativePath":"appium/packages/execute-driver-plugin/README.md"}},{"pageContent":"# @appium/fake-driver\n\n> Fake Appium driver for internal testing\n\n# @appium/fake-driver > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/fake-driver","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/fake-driver/README.md"}},{"pageContent":"# @appium/fake-plugin\n\n> Fake Appium plugin for internal testing\n\n# @appium/fake-plugin > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/fake-plugin","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/fake-plugin/README.md"}},{"pageContent":"# @appium/images-plugin\n\n> Appium plugin for image comparison, visual testing, and image-based functional testing\n\n[![NPM version](http://img.shields.io/npm/v/@appium/images-plugin.svg)](https://npmjs.org/package/@appium/images-plugin)\n[![Downloads](http://img.shields.io/npm/dm/@appium/images-plugin.svg)](https://npmjs.org/package/@appium/images-plugin)\n\n# @appium/images-plugin > ## Features\n\n1. **Image Comparison** ([docs](./docs/image-comparison.md)) - A new Appium command and route that allows sending in two different images and comparing them in various ways.\n2. **Finding Elements by Image** ([docs](./docs/find-by-image.md)) - Using a template image, find a matching screen region of an app and interact with it via standard Appium element semantics.\n\n# @appium/images-plugin > ## Installation\n\n```\nappium plugin install images\n```\n\nThe plugin must be explicitly activated when launching the Appium server:\n\n```\nappium --use-plugins=images\n```\n\n# @appium/images-plugin > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/images-plugin","sectionCount":4,"filename":"README.md","relativePath":"appium/packages/images-plugin/README.md"}},{"pageContent":"## Finding and Interacting with Image Elements\n\nUsing the `-image` locator strategy supported by this plugin, it is possible to send an Appium an image file representing an element you want to tap. If Appium can find a screen region matching your template, it will wrap up information about this region as a standard `WebElement` and send it back to your Appium client.\n\nThe strategy will be made available differently for each Appium client, for example: `driver.findElementByImage()`.\n\n## Finding and Interacting with Image Elements > ### Image Selectors\n\nIn conjunction with any locator strategy, you need to use a \"selector\" which details the specific nature of your find request. In the case of the `-image` strategy, the selector must be a string which is a base64-encoded image file representing the template you want to use for matching.\n\n## Finding and Interacting with Image Elements > ### Image Elements\n\nIf the image match is successful, Appium will cache information about the match and create a standard response for your client to consume, resulting in the instantiation of a standard element object in your test script. Using this element object, you are able to call a small number of methods on the \"Image Element\", as if it were a bona-fide `WebElement`:\n\n* `click`\n* `isDisplayed`\n* `getSize`\n* `getLocation`\n* `getLocationInView`\n* `getElementRect`\n* `getAttribute`\n * `visual` returns matched image as base64 data if `getMatchedImageResult` is `true`\n * `score` returns the similarity score as a float number in range `[0.0, 1.0]` sine Appium 1.18.0\n\nThese actions are supported on \"Image Elements\" because they are the actions which involve only use of screen position for their functioning. Other actions (like `sendKeys`, for example) are not supported, because all Appium can know based on your template image is whether or not there is a screen region which visually matches it--Appium has no way of turning that information into a driver-specific UI element object, which would be necessary for the use of other actions.\n\nIt's important to keep this important point in mind: there is nothing \"magic\" about Image Elements---they merely reference screen coordinates, and thus \"tapping\" an Image Element is internally nothing more than Appium constructing a tap at a point in the center of the Image Element's screen bounds (and in fact you can tell Appium which API to use to perform that tap---see below).","metadata":{"headerPath":"## Finding and Interacting with Image Elements","sectionCount":3,"filename":"find-by-image.md","relativePath":"appium/packages/images-plugin/docs/find-by-image.md"}},{"pageContent":"## Finding and Interacting with Image Elements > ### Related Settings\n\nBecause finding elements by image relies on image analysis software in conjunction with Appium's screenshot functionality and the reference images you yourself provide, we provide a number of settings that help you modulate this feature, in some cases potentially speeding up the match or making it more accurate.\n\nTo access these settings, you should use the Appium [Settings API](http://appium.io/docs/en/latest/guides/settings/), or pre-set any settings as capabilities using the [special `settings[]` capability](http://appium.io/docs/en/latest/guides/settings/#initializing-settings-via-capabilities). These are the settings that are available:","metadata":{"headerPath":"## Finding and Interacting with Image Elements > ### Related Settings","sectionCount":1,"recursiveSplit":true,"filename":"find-by-image.md","relativePath":"appium/packages/images-plugin/docs/find-by-image.md"}},{"pageContent":"## Finding and Interacting with Image Elements > ### Related Settings\n\n|Setting Name|Description|Possible Values|Default Value|\n|------------|-----------|---------------|-------------|\n|imageMatchThreshold|The OpenCV match threshold below which to consider the find a failure. Basically the range of possibilities is between 0 (which means no threshold should be used) and 1 (which means that the reference image must be an exact pixel-for-pixel match). The exact values in between have no absolute meaning. For example a match that requires drastic resizing of a reference image will come out as a lower match strength than otherwise. It's recommended you try the default setting, and then incrementally lower the threshold if you're not finding matching elements. If you're matching the wrong element, try increasing the threshold value.|Numbers from 0 to 1|0.4|\n|fixImageFindScreenshotDims|Appium knows the screen dimensions, and ultimately these are the dimensions which are relevant for deciding where to tap on the screen. If the screenshot retrieved (via Appium's native methods, or an external source) does not match the screen dimensions, this setting dictates that Appium will adjust the size of the screenshot to match, ensuring that matched elements are found at the correct coordinates. Turn this setting off if you know it's not necessary, and Appium will forego the check, potentially speeding things up a bit.|`true` or `false`|`true`|\n|fixImageTemplateSize|OpenCV will not allow the matching of a reference image / template if that image is larger than the base image to match against. It can happen that the reference image you send in has dimensions which are larger than the screenshot Appium retrieves. In this case the match will automatically fail. If you set this setting to `true`, Appium will resize the template to ensure it is at least smaller than the size of the screenshot.|`true` or `false`|`false`|","metadata":{"headerPath":"## Finding and Interacting with Image Elements > ### Related Settings","sectionCount":1,"recursiveSplit":true,"filename":"find-by-image.md","relativePath":"appium/packages/images-plugin/docs/find-by-image.md"}},{"pageContent":"## Finding and Interacting with Image Elements > ### Related Settings\n\n|fixImageTemplateScale| Appium resizes a base image to fit its window size before matching them with OpenCV. If you set this setting to `true`, Appium scales a reference image you send in as the same scale Appium scales the base image to fit the window size. e.g. iOS screenshot is `750 × 1334` pixels base image. The window size is `375 x 667`. Appium rescale the base image to window size scaling it with `0.5`. A reference image is based on the screenshot size, never the image matches with the window size scale. This settings allow Appium to scale the reference image with `0.5`. [appium-base-driver#306](https://github.com/appium/appium-base-driver/pull/306)| `true` or `false` | `false` |\n|defaultImageTemplateScale| Appium does not resize template images by default (the value of 1.0). Although, storing scaled template images might help to save size of the storage. E.g. One could represent 1080 × 126 pixels area by 270 × 32 pixels template image (the value of defaultImageTemplateScale is expected to be set to 4.0). Check [appium-base-driver#307](https://github.com/appium/appium-base-driver/pull/307) for more details. |e.g., `0.5`, `10.0`, `100`| `1.0` |\n|checkForImageElementStaleness|It can happen that, in between the time you have matched an image element and the time you choose to tap on it, the element is no longer present. The only way for Appium to determine this is to attempt to re-match the template immediately before tapping. If that re-match fails, you will get a `StaleElementException`, as you would expect. Turn this to `false` to skip the check, potentially speeding things up, but potentially running into stale element issues without the benefit of an exception to let you know you did.|`true` or `false`|`true`|\n|autoUpdateImageElementPosition|It can happen that a matched image changes position in between the time it is found and the time you tap on it. As with the previous setting, Appium can automatically adjust its position if it determines in a re-match that the position changed.|`true` or `false`|`false`|\n|imageElementTapStrategy|In order to tap on a found image element, Appium has to use one of its touch action strategies. The available strategies are the W3C Actions API, or the older MJSONWP TouchActions API. Stick to the default unless the driver you are using does not support the W3C Actions API for some reason.|`\"w3cActions\"` or `\"touchActions\"`|`\"w3cActions\"`|","metadata":{"headerPath":"## Finding and Interacting with Image Elements > ### Related Settings","sectionCount":1,"recursiveSplit":true,"filename":"find-by-image.md","relativePath":"appium/packages/images-plugin/docs/find-by-image.md"}},{"pageContent":"## Finding and Interacting with Image Elements > ### Related Settings\n\n|getMatchedImageResult| Appium does not store the matched image result. Although, storing the result in memory might help for debugging whether which area is matched by find by image. Appium returns the image against `attribute` API as `visual`. | `true` or `false` | `false` |","metadata":{"headerPath":"## Finding and Interacting with Image Elements > ### Related Settings","sectionCount":1,"recursiveSplit":true,"filename":"find-by-image.md","relativePath":"appium/packages/images-plugin/docs/find-by-image.md"}},{"pageContent":"## Finding and Interacting with Image Elements > ### Related Settings\n\nNote that each language-specific Appium client may make these settings available via special constants which could differ slightly from the exact setting names mentioned above.","metadata":{"headerPath":"## Finding and Interacting with Image Elements > ### Related Settings","sectionCount":1,"recursiveSplit":true,"filename":"find-by-image.md","relativePath":"appium/packages/images-plugin/docs/find-by-image.md"}},{"pageContent":"## Finding and Interacting with Image Elements > ### Debug\n\nThe `getMatchedImageResult` setting might help for debugging if Appium found the provided image expectedly. The returned element will have a `visual` attribute which will make comparison image available as base64 data if `getMatchedImageResult` is `true`.\n\n```ruby\n# Ruby core\n@driver.update_settings({ getMatchedImageResult: true })\nel = @driver.find_element_by_image 'path/to/img.ong'\nimg_el.visual # returns base64 encoded string\n```\n\n```python\n# Python\nself.driver.update_settings({\"getMatchedImageResult\": True})\nel = self.driver.find_element_by_image('path/to/img.ong')\nel.get_attribute('visual') # returns base64 encoded string\n```","metadata":{"headerPath":"## Finding and Interacting with Image Elements > ### Debug","sectionCount":1,"filename":"find-by-image.md","relativePath":"appium/packages/images-plugin/docs/find-by-image.md"}},{"pageContent":"# Image Comparison Features\n\nThis article describes the set of image comparison features available within the plugin. These features are available in all drivers and require OpenCV 3 native libs. Also, each feature is able to visualize the comparison result, so you can always track what is going on under the hood to select optimal matching parameters to achieve the best comparison results.\n\n# Image Comparison Features > ## Purpose\n\nImage comparison might be handy for many automation tasks. For example:\n* It is necessary to figure out whether the given picture example is present on the screen\n* It is necessary to calculate coordinates of some predefined on-screen object\n* It is necessary to verify whether the current on-screen object state is similar to the expected state\n\n# Image Comparison Features > ## Feature-based Comparison\n\nPerforms image matching by template to find possible occurrence of the partial image in the full image. Read [the OpenCV docs](https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_matcher/py_matcher.html) for more details on this topic. Such comparison is useful in the case where resulting image is rotated/scaled in relation to the original one.","metadata":{"headerPath":"# Image Comparison Features","sectionCount":3,"filename":"image-comparison.md","relativePath":"appium/packages/images-plugin/docs/image-comparison.md"}},{"pageContent":"# Image Comparison Features > ## Feature-based Comparison > ### Examples\n\n```java\n// java\n\nbyte[] screenshot = Base64.encodeBase64(driver.getScreenshotAs(OutputType.BYTES));\nFeaturesMatchingResult result = driver\n .matchImagesFeatures(screenshot, originalImg, new FeaturesMatchingOptions()\n .withDetectorName(FeatureDetector.ORB)\n .withGoodMatchesFactor(40)\n .withMatchFunc(MatchingFunction.BRUTE_FORCE_HAMMING)\n .withEnabledVisualization());\nassertThat(result.getVisualization().length, is(greaterThan(0)));\nassertThat(result.getCount(), is(greaterThan(0)));\nassertThat(result.getTotalCount(), is(greaterThan(0)));\nassertFalse(result.getPoints1().isEmpty());\nassertNotNull(result.getRect1());\nassertFalse(result.getPoints2().isEmpty());\nassertNotNull(result.getRect2());\n```\n\nAll the `FeaturesMatchingOptions` builder methods above contain detailed descriptions in their docstrings.\n\n```ruby\n# Ruby\nimage1 = File.read 'first/image/path.png'\nimage2 = File.read 'second/image/path.png'\n\nmatch_result = @driver.match_images_features first_image: image1, second_image: image2\nassert_equal %w(points1 rect1 points2 rect2 totalCount count), match_result.keys\n\nmatch_result_visual = @driver.match_images_features first_image: image1, second_image: image2, visualize: true\nassert_equal %w(points1 rect1 points2 rect2 totalCount count visualization), match_result_visual.keys\nFile.open('match_result_visual.png', 'wb') { |f| f<< Base64.decode64(match_result_visual['visualization']) }\nassert File.size? 'match_result_visual.png'\n```\n\n# Image Comparison Features > ## Feature-based Comparison > ### Visualization Example\n\n![Feature-Based Comparison Example](https://user-images.githubusercontent.com/7767781/38800997-f7408fb8-4168-11e8-93b9-cfe3d51ecf1c.png)","metadata":{"headerPath":"# Image Comparison Features > ## Feature-based Comparison > ### Examples","sectionCount":2,"filename":"image-comparison.md","relativePath":"appium/packages/images-plugin/docs/image-comparison.md"}},{"pageContent":"# Image Comparison Features > ## Occurrences Lookup\n\nPerforms images matching by template to find possible occurrence of the partial image in the full image. Read [the OpenCV template matching docs](https://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/template_matching/template_matching.html) for more details on this topic. Such comparison is useful in case the full image is a superset of the partial image.\n\nThere is a subtle difference between occurrence comparison and feature comparison. The former is to be used when the image to be found is a subset of the target/screenshot. The latter is to be used when the image to be found is basically the same as the target but rotated and/or scaled.","metadata":{"headerPath":"# Image Comparison Features > ## Occurrences Lookup","sectionCount":1,"filename":"image-comparison.md","relativePath":"appium/packages/images-plugin/docs/image-comparison.md"}},{"pageContent":"# Image Comparison Features > ## Occurrences Lookup > ### Examples\n\n```java\n// java\n\nbyte[] screenshot = Base64.encodeBase64(driver.getScreenshotAs(OutputType.BYTES));\nOccurrenceMatchingResult result = driver\n .findImageOccurrence(screenshot, partialImage, new OccurrenceMatchingOptions()\n .withEnabledVisualization());\nassertThat(result.getVisualization().length, is(greaterThan(0)));\nassertNotNull(result.getRect());\n```\n\nAll the `OccurrenceMatchingOptions` builder methods above contain detailed descriptions in their docstrings.\n\n```ruby\n# Ruby\nimage1 = File.read 'first/image/path.png'\nimage2 = File.read 'partial/image/path.png'\n\nfind_result = @driver.find_image_occurrence full_image: image1, partial_image: image2\nassert_equal({ 'rect' => { 'x' => 0, 'y' => 0, 'width' => 750, 'height' => 1334 } }, find_result)\n\nfind_result_visual = @driver.find_image_occurrence full_image: image1, partial_image: image2, visualize: true\nassert_equal %w(rect visualization), find_result_visual.keys\nFile.open('find_result_visual.png', 'wb') { |f| f<< Base64.decode64(find_result_visual['visualization']) }\nassert File.size? 'find_result_visual.png'\n```\n\n```javascript\n// Typescript / Javascript\n/*\n Typescsript code for occurrence comparison using the template matching algorithm.\n It detects if an image is contained in another image (called the template).\n The image must have the same scale and look the same. However, you can add a scaling transformation beforehand.\n\n official doc:\n https://github.com/appium/appium/blob/master/packages/images-plugin/docs/image-comparison.md\n OpenCV algorithm doc:\n https://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/template_matching/template_matching.html\n official sample code:\n https://github.com/justadudewhohacks/opencv4nodejs/blob/master/examples/templateMatching.js\n\n You must install opencv4nodejs using the -g option.\n\n The Javascript client driver webdriverio does not support (in January 2020) the \"-image\" strategy implemented in the Appium server. You will have more power and understanding while using openCV directly. Since the appium server is in Javascript, you can do all it does with opencv in your test suite.","metadata":{"headerPath":"# Image Comparison Features > ## Occurrences Lookup > ### Examples","sectionCount":1,"recursiveSplit":true,"filename":"image-comparison.md","relativePath":"appium/packages/images-plugin/docs/image-comparison.md"}},{"pageContent":"# Image Comparison Features > ## Occurrences Lookup > ### Examples\n\nThe testing framework mocha can be run with typescript to have async/await.\n You need to run mocha with those options in the right order and with the associated packages installed:\n NODE_PATH=/path/to/nodejs/lig/node_modules TS_NODE_PROJECT=config/tsconfig_test.json --require ts-node/register --require tsconfig-paths/register\n You will also need to make a basic config/tsconfig_test.json\n Note that paths in tsconfig.json does not support absolute paths. Hence, you cannot move the NODE_PATH there.\n*/\nimport * as path from 'path';\nconst cv = require(path.join(process.env.NODE_PATH, 'opencv4nodejs'));\nconst isImagePresent = async () => {\n /// Take screenshot and read the image\n const screenImagePath = './appium_screenshot1.png';\n await driver.saveScreenshot(screenImagePath)\n const likedImagePath = './occurrence1.png';\n\n // Load images\n const originalMatPromise = cv.imreadAsync(screenImagePath);\n const waldoMatPromise = cv.imreadAsync(likedImagePath);\n const [originalMat, waldoMat] = await Promise.all([originalMatPromise, waldoMatPromise]);\n\n // Match template (the brightest locations indicate the highest match)\n // In the OpenCV doc, the option 5 refers to the algorithm called CV_TM_CCOEFF_NORMED\n const matched = originalMat.matchTemplate(waldoMat, 5);\n\n // Use minMaxLoc to locate the highest value (or lower, depending of the type of matching method)\n const minMax = matched.minMaxLoc();\n const { maxLoc: { x, y } } = minMax;\n\n // Draw bounding rectangle\n originalMat.drawRectangle(\n new cv.Rect(x, y, waldoMat.cols, waldoMat.rows),\n new cv.Vec(0, 255, 0),\n 2,\n cv.LINE_8\n );\n\n // Open result in new window\n // If the image is too big for your screen, you need to write to a file instead.\n // Check the source of opencv4nodejs for writing an image to a file.\n cv.imshow('We\\'ve found Waldo!', originalMat);\n await cv.waitKey();\n\n // then you know if the image was found by comparing the rectangle with a reference rectangle.\n // the structure minMax contains the property maxVal that gives the quality of the match\n // 1 is prefect match, but you may get .999. If you extract an image from the screenshot manually,\n // you will get an image that matches.\n};\n```","metadata":{"headerPath":"# Image Comparison Features > ## Occurrences Lookup > ### Examples","sectionCount":1,"recursiveSplit":true,"filename":"image-comparison.md","relativePath":"appium/packages/images-plugin/docs/image-comparison.md"}},{"pageContent":"# Image Comparison Features > ## Occurrences Lookup > ### Visualization Example\n\n![Occurrences Lookup](https://user-images.githubusercontent.com/7767781/40233298-b7decfe4-5aa2-11e8-8c9b-f85f384d2092.png)\n\nThe highlighted picture at the left bottom corner is the resulting match of ![Waldo](https://github.com/appium/appium-support/blob/master/test/images/waldo.jpg?raw=true) lookup.\n\n# Image Comparison Features > ## Similarity Calculation\n\nPerforms images matching to calculate the similarity score between them. The flow there is similar to the one used in `findImageOccurrence`, but it is mandatory that both images are of equal size. Such comparison is useful in case the original image is a copy of the original one, but with changed content.\n\n# Image Comparison Features > ## Similarity Calculation > ### Examples\n\n```java\n// java\n\nbyte[] screenshot1 = Base64.encodeBase64(driver.getScreenshotAs(OutputType.BYTES));\nbyte[] screenshot2 = Base64.encodeBase64(driver.getScreenshotAs(OutputType.BYTES));\nSimilarityMatchingResult result = driver\n .getImagesSimilarity(screenshot1, screenshot2, new SimilarityMatchingOptions()\n .withEnabledVisualization());\nassertThat(result.getVisualization().length, is(greaterThan(0)));\nassertThat(result.getScore(), is(greaterThan(0.0)));\n```\n\nAll the `SimilarityMatchingOptions` builder methods above contain detailed descriptions in their docstrings.\n\n```ruby\n# Ruby\nimage1 = File.read 'first/image/path.png'\nimage2 = File.read 'second/image/path.png'\n\nget_images_result = @driver.get_images_similarity first_image: image1, second_image: image2\nassert_equal({ 'score' => 0.891606867313385 }, get_images_result)\n\nget_images_result_visual = @driver.get_images_similarity first_image: image1, second_image: image2, visualize: true\nassert_equal %w(score visualization), get_images_result_visual.keys\nFile.open('get_images_result_visual.png', 'wb') { |f| f<< Base64.decode64(get_images_result_visual['visualization']) }\nassert File.size? 'get_images_result_visual.png'\n```\n\n# Image Comparison Features > ## Similarity Calculation > ### Visualization Example\n\n![Similarity Matching Example](https://user-images.githubusercontent.com/7767781/38780635-27198346-40da-11e8-803d-1ec4afd3c3aa.png)\n\nThe similarity score for two pictures above is ~0.98.","metadata":{"headerPath":"# Image Comparison Features > ## Occurrences Lookup > ### Visualization Example","sectionCount":4,"filename":"image-comparison.md","relativePath":"appium/packages/images-plugin/docs/image-comparison.md"}},{"pageContent":"# @appium/logger\n\n> Appium's logging functionality\n\n# @appium/logger > ## Installation\n\n```console\nnpm install @appium/logger --save\n```\n\n# @appium/logger > ## Basic Usage\n\n```js\nimport log from '@appium/logger';\n\n// additional stuff ---------------------------+\n// message ----------+ |\n// prefix ----+ | |\n// level -+ | | |\n// v v v v\n log.info('fyi', 'I have a kitty cat: %j', myKittyCat);\n```\n\n# @appium/logger > ## History\n\nThis module is forked from [npmlog](https://github.com/npm/npmlog) under ISC License because the original project has been archived.\nPlease check [the npmlog changelog](https://github.com/npm/npmlog/blob/main/CHANGELOG.md) to see the list of former module updates before it was forked.\n\n# @appium/logger > ## License\n\nISC License","metadata":{"headerPath":"# @appium/logger","sectionCount":5,"filename":"README.md","relativePath":"appium/packages/logger/README.md"}},{"pageContent":"# @appium/opencv\n\n> OpenCV-related helper methods\n\n[![NPM version](http://img.shields.io/npm/v/@appium/opencv.svg)](https://npmjs.org/package/@appium/opencv)\n[![Downloads](http://img.shields.io/npm/dm/@appium/opencv.svg)](https://npmjs.org/package/@appium/opencv)\n\n# @appium/opencv > ## Installation\n\n`npm install @appium/opencv`\n\n# @appium/opencv > ## Usage\n\n# @appium/opencv > ## Usage > ### initOpenCv\n\nLoads the opencv bindings. You only need to explicitly call this if you want to use your own opencv\nmethods that are not included in this module.\n\n```js\nimport {initOpenCv} from '@appium/opencv';\nawait initOpenCv();\n```\n\n# @appium/opencv > ## Usage > ### getImagesMatches\n\nCalculates the count of common edges between two images. The images might be rotated or resized\nrelatively to each other. See the function definition for more details.\n\n```js\nimport {getImagesMatches} from '@appium/opencv';\nimport {fs} from '@appium/support';\n\nconst image1 = await fs.readFile('image1.jpg')\nconst image2 = await fs.readFile('image2.jpg')\nconst {points1, rect1, points2, rect2, totalCount, count} = await getImagesMatches(image1, image2);\n```\n\n# @appium/opencv > ## Usage > ### getImagesSimilarity\n\nCalculates the similarity score between two images. It is expected that both images have the same\nresolution. See the function definition for more details.\n\n```js\nimport {getImagesSimilarity} from '@appium/opencv';\nimport {fs} from '@appium/support';\n\nconst image1 = await fs.readFile('image1.jpg')\nconst image2 = await fs.readFile('image2.jpg')\nconst {score} = await getImagesSimilarity(image1, image2);\n```\n\n# @appium/opencv > ## Usage > ### getImageOccurrence\n\nCalculates the occurrence position of a partial image in the full image. See the function definition\nfor more details.\n\n```js\nimport {getImageOccurrence} from '@appium/opencv';\nimport {fs} from '@appium/support';\n\nconst fullImage = await fs.readFile('image1.jpg')\nconst partialImage = await fs.readFile('image2.jpg')\nconst {rect, score} = await getImageOccurrence(fullImage, partialImage);\n```\n\n# @appium/opencv > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/opencv","sectionCount":8,"filename":"README.md","relativePath":"appium/packages/opencv/README.md"}},{"pageContent":"# @appium/plugin-test-support\n\n> Testing utilities for [Appium](https://appium.io) plugins\n\nThis package is for plugin authors to help test their plugins.\n\n[Mocha](https://mochajs.org) is the supported test framework (but can theoretically be used with others).\n\n# @appium/plugin-test-support > ## Usage\n\n# @appium/plugin-test-support > ## Usage > ### For E2E Tests\n\nThe `pluginE2EHarness` method configures a server and driver for testing via \"before all\" and \"after all\"-style hooks.\n\nThis example uses [WebdriverIO](https://webdriver.io) to communicate with a test Appium server.\n\n```js\nimport {pluginE2EHarness} from '@appium/plugin-test-support';\nimport {remote} from 'webdriverio';\n\ndescribe('MyPlugin', function() {\n pluginE2EHarness({\n before: global.before, // from mocha\n after: global.after, // from mocha\n serverArgs: SOME_EXTRA_SERVER_ARGS,\n port: 31337,\n host: '127.0.0.1',\n appiumHome: process.env.APPIUM_HOME, // best practice: use a temp dir instead\n driverName: 'fake', // driver to test with\n driverSource: 'local', // use \"local\" unless you want appium to install from npm every time\n driverSpec: FAKE_DRIVER_DIR, // path to local driver working copy or installation\n pluginName: 'MyPlugin', // your plugin \n pluginSource: 'local', // use \"local\" for this\n pluginSpec: THIS_PLUGIN_DIR, // dir of this plugin's `package.json`\n });\n\n it('should use my plugin', async function() {\n // at this point, the Appium server will be running with the plugin/driver combination of your\n // choosing\n\n // port/host should match what you provided to `pluginE2EHarness`\n const browser = await remote({port: 31337, hostname: '127.0.0.1'});\n })\n});\n```\n\n# @appium/plugin-test-support > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/plugin-test-support","sectionCount":4,"filename":"README.md","relativePath":"appium/packages/plugin-test-support/README.md"}},{"pageContent":"# @appium/relaxed-caps-plugin\n\n> Appium plugin for handling extension capabilities with no prefix\n\n[![NPM version](http://img.shields.io/npm/v/@appium/relaxed-caps-plugin.svg)](https://npmjs.org/package/@appium/relaxed-caps-plugin)\n[![Downloads](http://img.shields.io/npm/dm/@appium/relaxed-caps-plugin.svg)](https://npmjs.org/package/@appium/relaxed-caps-plugin)\n\nAppium conforms to the W3C WebDriver Protocol [requirements for capabilities](https://www.w3.org/TR/webdriver/#capabilities),\nwhich means that all non-standard (extension) capabilities used with Appium must have a prefix\n(usually this prefix is `appium:`). Any non-standard capabilities without a prefix are rejected.\n\nThis plugin can be used to automatically add the `appium:` prefix to non-standard capabilities that\ndo not have a prefix.\n\n# @appium/relaxed-caps-plugin > ## Motivation\n\nThere are a lot of test scripts out there that don't conform to the W3C capability requirements,\nso this plugin is designed to make it easy to keep running these scripts even with the stricter\ncapability requirements since Appium 2.\n\n# @appium/relaxed-caps-plugin > ## Installation\n\n```\nappium plugin install relaxed-caps\n```\n\nThe plugin must be explicitly activated when launching the Appium server:\n\n```\nappium --use-plugins=relaxed-caps\n```\n\n# @appium/relaxed-caps-plugin > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/relaxed-caps-plugin","sectionCount":4,"filename":"README.md","relativePath":"appium/packages/relaxed-caps-plugin/README.md"}},{"pageContent":"# @appium/schema\n\n> JSON schema for [Appium](https://github.com/appium/appium) configuration files\n\n# @appium/schema > ## Description\n\nThis package is used internally by Appium, but can also be used to validate Appium configuration files in other contexts.\n\n# @appium/schema > ## Install\n\n```bash\nnpm i @appium/schema\n```\n\n# @appium/schema > ## Usage\n\nThe schema is exported as a JS object:\n\n```js\nconst { AppiumConfigJsonSchema } = require('@appium/schema');\n```\n\nIt is also provided as a JSON file (since this is a JSON schema, after all):\n\n```js\nconst schema = require('@appium/schema/lib/appium-config.schema.json');\n```\n\n# @appium/schema > ## See Also\n\n[@appium/types](https://npm.im/@appium/types) exports a TypeScript type `AppiumConfig` (generated from this package) for typesafe configuration objects; this may be useful if your Appium configuration is written in JS (e.g., `.appiumrc.js`). Example:\n\n```js\n// @ts-check\n/** @type {import('@appium/types').AppiumConfig} */\nmodule.exports = {\n server: {\n port: 1234,\n host: '127.0.0.1'\n }\n}\n```\n\n# @appium/schema > ## Notes\n\n`lib/appium-config.schema.json` is generated by this package from `lib/appium-config-schema.js` (the single source of truth), but is under version control to avoid chicken-or-egg build problems.\n\n# @appium/schema > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/schema","sectionCount":7,"filename":"README.md","relativePath":"appium/packages/schema/README.md"}},{"pageContent":"# @appium/storage-plugin\n\n> Appium plugin for server-side file storage\n\nThis plugin adds the ability to create a dedicated storage space on the server side,\nwhich can be managed from the client side. This can be useful for files like application packages.\nOnly one storage may exist per server process, shared by all testing sessions.\n\n> [!WARNING]\n> This plugin is designed to be used with servers deployed in private networks.\n> Consider validating the setup with your security department\n> if you want to enable this plugin at a public Appium server deployment.\n\n# @appium/storage-plugin > ## Installation\n\n```bash\nappium plugin install storage\n```\n\n# @appium/storage-plugin > ## Usage\n\nAdd the plugin name to the list of plugins to use upon server startup:\n\n```bash\nappium --use-plugins=storage\n```\n\nBy default, the plugin creates a new temporary folder where it manages uploaded files.\n\n[Refer to the Appium documentation for the endpoints supported by this plugin.](https://appium.io/docs/en/latest/reference/api/storage-plugin/)","metadata":{"headerPath":"# @appium/storage-plugin","sectionCount":3,"filename":"README.md","relativePath":"appium/packages/storage-plugin/README.md"}},{"pageContent":"# @appium/storage-plugin > ## Usage > ### Storing a File\n\nThe procedure for storing a local file on the Appium server is as follows:\n\n- Calculate the [SHA1](https://en.wikipedia.org/wiki/SHA-1) hash of the source file\n- Decide the name of the destination file in the server storage (it can be the same as the original file name)\n- Send a `POST` request to the `/storage/add` endpoint, which will return the `events` and `stream` websocket paths\n- Connect to both web sockets\n- Start listening for messages on the `events` web socket. Each message there is a JSON object wrapped\n to a string. The message must be either `{\"value\": {\"success\": true, \"name\":\"app.ipa\",\"sha1\":\"ccc963411b2621335657963322890305ebe96186\"}}` to notify about a successful\n file upload, or `{\"value\": {\"error\": \"<error signature>\", \"message\": \"<error message>\", \"traceback\": \"<server traceback>\"}}`\n to notify about any exceptions during the upload process.\n- Start reading the source file into small chunks. The recommended size of a single chunk is 64 KB.\n- After each chunk is retrieved, pass it to the `stream` web socket.\n- After the last chunk upload is completed, either close the `stream` web\n socket to explicitly notify the server about the upload completion, or\n wait until the success event is delivered from the `events` web socket\n as soon as file hashes successfully match.\n The server must always deliver either a success or a failure\n event via the `events` web socket as described above.\n\nIt is also possible to upload multiple files in parallel (up to 20 jobs are supported).\nOnly flat files hierarchies are supported in the storage, no subfolders are allowed.\nIf a file with the same name already exists in the storage, it will be overridden with the new one.\nIf a folder with the same name already exists in the storage, an error will be thrown.\n\n# @appium/storage-plugin > ## Usage > ### Environment Variables","metadata":{"headerPath":"# @appium/storage-plugin > ## Usage > ### Storing a File","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/storage-plugin/README.md"}},{"pageContent":"# @appium/storage-plugin > ## Usage > ### Environment Variables > #### APPIUM_STORAGE_ROOT\n\nIt is also possible to customize the repository root folder path by assigning a custom path to the\n`APPIUM_STORAGE_ROOT` environment variable upon server startup. The plugin automatically deletes the\nroot folder recursively upon server process termination, unless the server is\nkilled forcefully. If `APPIUM_STORAGE_ROOT` points to an existing folder,\nthen all files there are going to be preserved by default unless a different behavior is\nrequested by [APPIUM_STORAGE_KEEP_ALL](#appium_storage_keep_all) environment variable value.\n\n# @appium/storage-plugin > ## Usage > ### Environment Variables > #### APPIUM_STORAGE_KEEP_ALL\n\nIf this environment variable is set to `true`, `1` or `yes` then the plugin will always keep\nstorage files after the server process is terminated. All other\nvalues of this variable enforce the plugin to always delete all files\nfrom the storage folder.\n\n# @appium/storage-plugin > ## Examples\n\nCheck [integration tests](./test/e2e/storage.e2e.spec.cjs) for a working\n[WebdriverIO](https://webdriver.io/) example.\n\n# @appium/storage-plugin > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/storage-plugin > ## Usage > ### Environment Variables > #### APPIUM_STORAGE_ROOT","sectionCount":4,"filename":"README.md","relativePath":"appium/packages/storage-plugin/README.md"}},{"pageContent":"# @appium/strongbox\n\n> Persistent storage for Appium extensions\n\n# @appium/strongbox > ## Summary\n\nThis package is intended to be used in [Appium](https://appium.io) extensions which need to persist data between Appium runs. An example of such data may be a device token or key. \n\n`@appium/strongbox` provides a simple and extensible API for managing such data, while abstracting the underlying storage mechanism.\n\n_Note:_ This module is not intended for storing sensitive data.\n\n# @appium/strongbox > ## Usage\n\nFirst, create an instance of `Strongbox`:\n\n```ts\nimport {strongbox} from '@appium/strongbox';\n\nconst box = strongbox('my-pkg');\n```\n\nThis instance corresponds to a unique collection of data.\n\nFrom here, create a placeholder for data (you will need to provide the type of data you intend to store):\n\n```ts\nconst item = await box.createItem<string>('my unique name');\n```\n\n...or, if you already have the data on-hand:\n\n```ts\nconst item: Buffer|string = getSomeData();\n\nconst item = await box.createItemWithContents('my unique name', data);\n```\n\nEither way, you can read its contents:\n\n```ts\n// if the item doesn't exist, this result will be undefined\nconst contents = await item.read();\n```\n\nOr write new data to the item:\n\n```ts\nawait item.write('new stuff');\n```\n\nThe last-read contents of the `Item` will be available on the `contents` property, but the value of this property is only current as of the last `read()`:\n\n```ts\nconst {contents} = item;\n```\n\n# @appium/strongbox > ## API\n\nIn lieu of actual documentation, look at the type definitions that this package ships.\n\n# @appium/strongbox > ## Customization\n\n1. Create a class that implements the `Item` interface:\n\n ```ts\n import {strongbox, Item} from '@appium/strongbox';\n import {Foo, getFoo} from 'somewhere/else';\n\n class FooItem implements Item<Foo> {\n // ...\n }\n ```\n\n2. Provide this class as the `defaultCtor` option to `strongbox()`:\n\n ```ts\n const box = strongbox('my-pkg', {defaultCtor: FooItem});\n ```\n\n3. Use like you would any other `Strongbox` instance:\n\n ```ts\n const foo: Foo = getFoo();\n const item = await box.createItemWithValue('my unique name', Foo);\n ```","metadata":{"headerPath":"# @appium/strongbox","sectionCount":5,"filename":"README.md","relativePath":"appium/packages/strongbox/README.md"}},{"pageContent":"# @appium/strongbox > ## Default Behavior, For the Curious\n\nOut-of-the-box, a `Strongbox` instance corresponds to a directory on-disk, and each `Item` (returned by `createItem()/createItemWithContents()`) corresponds to a file within that directory. \n\nThe directory of the `Strongbox` instance is determined by the [env-paths](https://www.npmjs.com/package/env-paths) package, and is platform-specific.\n\n# @appium/strongbox > ## License\n\nCopyright © 2023 OpenJS Foundation. Licensed Apache-2.0","metadata":{"headerPath":"# @appium/strongbox > ## Default Behavior, For the Curious","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/strongbox/README.md"}},{"pageContent":"# @appium/support\n\n> Utility functions used to support Appium drivers and plugins\n\n[![NPM version](http://img.shields.io/npm/v/@appium/support.svg)](https://npmjs.org/package/@appium/support)\n[![Downloads](http://img.shields.io/npm/dm/@appium/support.svg)](https://npmjs.org/package/@appium/support)\n\n# @appium/support > ## Usage in drivers and plugins\n\nDrivers and plugins are recommended to have Appium as a peer dependency, as it already includes\nthese utility functions. Add the following line to `peerDependencies` section of your module's\n`package.json`:\n\n```js\n \"peerDependencies\": {\n \"appium\": \"^<minimum_server_version>\"\n }\n```\n\nAfterwards import it in your code similarly to the below example:\n\n```js\nimport {timing, util} from 'appium/support';\n```\n\n# @appium/support > ## Usage in helper modules\n\nIf you want to use this module in a helper library, which is not a driver or a plugin,\nthen add the following line to `dependencies` section of your module's `package.json`:\n\n```js\n \"dependencies\": {\n \"@appium/support\": \"<module_version>\"\n }\n```\n\nAfterwards import it in your code similarly to the below example:\n\n```js\nimport {timing, util} from '@appium/support';\n```","metadata":{"headerPath":"# @appium/support","sectionCount":3,"filename":"README.md","relativePath":"appium/packages/support/README.md"}},{"pageContent":"# @appium/support > ## Categories\n\nAll utility functions are split into a bunch of different categories. Each category has its own file under the `lib` folder. All utility functions in these files are documented.\n\n|Category|Description|\n|-|-|\n|console|Wrappers for the command line interface abstraction used by the Appium server|\n|doctor|Common doctor utilities that can be used by drivers and plugins|\n|env|Several helpers needed by the server to cope with internal dependencies and manifests|\n|fs|Most of the functions here are just thin wrappers over utility functions available in [Promises API](https://nodejs.org/api/fs.html#promises-api)|\n|image-util|Utilities to work with images. Use [sharp](https://github.com/lovell/sharp) under the hood.<br>:bangbang: Node >=18.17 is required to use these utilities|\n|logging|See [the logging section below](#logging)|\n|mjpeg|Helpers needed to implement [MJPEG streaming](https://en.wikipedia.org/wiki/Motion_JPEG#Video_streaming)|\n|net|Helpers needed for network interactions, for example, upload and download of files|\n|node|Set of Node.js-specific utility functions needed, for example, to ensure objects immutability or to calculate their sizes|\n|npm|Set of `npm`-related helpers|\n|plist|Set of utilities used to read and write data from [plist](https://en.wikipedia.org/wiki/Property_List) files in javascript|\n|process|Helpers for interactions with system processes. These APIs don't support Windows.|\n|system|Set of helper functions needed to determine properties of the current operating system|\n|tempdir|Set of helpers that allow interactions with temporary folders|\n|timing|Helpers that allow to measure execution time|\n|util|Miscellaneous utilities|\n|zip|Helpers that allow to work with archives in `.zip ` format|\n\n# @appium/support > ## logging\n\nThis is a basic logger defaulting to [npmlog](https://github.com/npm/npmlog) with special\nconsideration for running tests (doesn't output logs when run with `_TESTING=1`).","metadata":{"headerPath":"# @appium/support > ## Categories","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/support/README.md"}},{"pageContent":"# @appium/support > ## logging > ### Logging levels\n\nThere are a number of levels, exposed as methods on the log object, at which logging can be made.\nThe built-in ones correspond to those of [npmlog](https://github.com/npm/npmlog#loglevelprefix-message-),\nand are: `silly`, `verbose`, `info`, `http`, `warn`, and `error`. There is also a `debug` level.\n\nThe default threshold level is `verbose`.\n\nThe logged output, by default, will be `level prefix message`. So\n\n```js\nimport {logging} from 'appium/support';\nlet log = logging.getLogger('mymodule');\nlog.warn('a warning');`\n```\n\nWill produce\n\n```shell\nwarn mymodule a warning\n```\n\n# @appium/support > ## logging > ### Environment variables\n\nThere are two environment variable flags that affect the way `logger` works.\n\n|Variable|Description|\n|-|-|\n|`_TESTING`|If set to `1`, logging output is stopped|\n|`_FORCE_LOGS`|If set to `1`, overrides the value of `_TESTING`|","metadata":{"headerPath":"# @appium/support > ## logging > ### Logging levels","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/support/README.md"}},{"pageContent":"# @appium/support > ## logging > ### Usage\n\n`log.level`\n\n- Get and set the threshold level at which to display the logs. Any logs at or above this level will\nbe displayed. The special level `silent` will prevent anything from being displayed ever. See\n[npmlog#level](https://github.com/npm/npmlog#loglevel) for more details.\n\n`log[level](message)`\n\n- Logs `message` at the specified `level`\n```js\nimport {logging} from 'appium/support';\nlet log = logging.getLogger('mymodule');\n\nlog.info('hi!');\n// => info mymodule hi!\n```\n\n`log.unwrap()`\n\n- Retrieves the underlying [npmlog](https://github.com/npm/npmlog) object, in order to manage how\nlogging is done at a low level (e.g., changing output streams, retrieving an array of messages,\nadding log levels, etc.).\n\n```js\nimport {logging} from 'appium/support';\nlet log = logging.getLogger('mymodule');\n\nlog.info('hi!');\n\nlet npmlogger = log.unwrap();\n\n// any `npmlog` methods\nlet logs = npmlogger.record;\n// logs === [ { id: 0, level: 'info', prefix: 'mymodule', message: 'hi!', messageRaw: [ 'hi!' ] }]\n```\n\n`log.errorWithException(error)`\n\n- Logs the error passed in, at `error` level, and then returns the error. If the error passed in is\nnot an instance of [Error](https://nodejs.org/api/errors.html#errors_class_error) (either directly,\nor a subclass of `Error`), it will be wrapped in a generic `Error` object.\n\n```js\nimport {logging} from 'appium/support';\nlet log = logging.getLogger('mymodule');\n\n// previously there would be two lines\nlog.error('This is an error');\nthrow new Error('This is an error');\n\n// now is compacted\nthrow log.errorWithException('This is an error');\n```\n\n# @appium/support > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/support > ## logging > ### Usage","sectionCount":2,"filename":"README.md","relativePath":"appium/packages/support/README.md"}},{"pageContent":"# @appium/test-support\n\n> A collection of test utility libs used across Appium packages\n\n[![NPM version](http://img.shields.io/npm/v/@appium/test-support.svg)](https://npmjs.org/package/@appium/test-support)\n[![Downloads](http://img.shields.io/npm/dm/@appium/test-support.svg)](https://npmjs.org/package/@appium/test-support)\n\n# @appium/test-support > ## Installation\n\n```\nnpm install @appium/test-support --save-dev\n```\n\n# @appium/test-support > ## Usage\n\n# @appium/test-support > ## Usage > ### withSandbox\n\nUse when mixing up `sinon` APIs (mocks, spies, stubs).\n\n```js\nimport { withSandbox } from '@appium/test-support';\n\nlet api = {\n abc: () => { return 'abc'; }\n};\n\ndescribe('MyTest', withSandbox({mocks: {api}}, (S) => {\n it('stubbing api, stubbing dog', () => {\n S.mocks.api.expects('abc').once().returns('efg');\n let dog = { bark: () => { return 'ouaf!'; } };\n S.sandbox.stub(dog, 'bark').returns('miaou');\n api.abc().should.equal('efg');\n dog.bark().should.equal('miaou');\n S.verify();\n });\n}));\n```\n\n# @appium/test-support > ## Usage > ### withMocks\n\nWhen using mainly stubs.\n\n```js\nimport { withMocks } from '@appium/test-support';\n\nlet api = {\n abc: () => { return 'abc'; }\n};\n\ndescribe('withMocks', withMocks({api}, (mocks) => {\n it('should mock api', () => {\n mocks.api.expects('abc').once().returns('efg');\n api.abc().should.equal('efg');\n mocks.verify();\n });\n}));\n```\n\n# @appium/test-support > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/test-support","sectionCount":6,"filename":"README.md","relativePath":"appium/packages/test-support/README.md"}},{"pageContent":"# @appium/tsconfig\n\n> Shared TypeScript Config for Appium\n\n# @appium/tsconfig > ## Motivation\n\nAppium projects and extensions are encouraged to use these settings.\n\n# @appium/tsconfig > ## Install\n\n```bash\nnpm install appium @appium/tsconfig -D\n```\n\n[appium](https://npm.im/appium) is a peer dependency of this package.\n\n# @appium/tsconfig > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/tsconfig","sectionCount":4,"filename":"README.md","relativePath":"appium/packages/tsconfig/README.md"}},{"pageContent":"# @appium/types\n\n> A collection of TypeScript type declarations used across various [Appium](https://github.com/appium/appium) packages.\n\n> [!WARNING]\n> This is a work-in-progress; expect breaking changes!\n\n# @appium/types > ## Install\n\n```bash\nnpm install @appium/types -D\n```\n\n> [!NOTE]\n> - The sources are `.ts` files, _not_ `.d.ts` files. This allows other packages in the root TypeScript \"project\" to define a dependency upon this one, and enables incremental builds an \"watch\" mode.\n> - If there is a way to switch to `.d.ts` files and configure this package to work in our \"project\" context _without_ needing to actually \"emit\" anything, then we should do that instead. Help accepted!\n> - `lib/appium-config.ts` is generated by this package from `@appium/schema`, but is under version control to avoid chicken-or-egg build problems.\n\n# @appium/types > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/types","sectionCount":3,"filename":"README.md","relativePath":"appium/packages/types/README.md"}},{"pageContent":"# @appium/universal-xml-plugin\n\n> Appium plugin for transforming platform-specific XML into a universal syntax\n\n[![NPM version](http://img.shields.io/npm/v/@appium/universal-xml-plugin.svg)](https://npmjs.org/package/@appium/universal-xml-plugin)\n[![Downloads](http://img.shields.io/npm/dm/@appium/universal-xml-plugin.svg)](https://npmjs.org/package/@appium/universal-xml-plugin)\n\nThis plugin takes the XML page source retrieved using an iOS or Android driver, and changes various\nnode and attribute names to use common terminology that can apply to both platforms. This is\nachieved by altering the behavior of the `getPageSource` and `findElement` methods.\n\n# @appium/universal-xml-plugin > ## Motivation\n\nHaving compatibility between iOS and Android XML sources can simplify creation of cross-platform tests.\n\n# @appium/universal-xml-plugin > ## Installation\n\n```\nappium plugin install universal-xml\n```\n\nThe plugin must be explicitly activated when launching the Appium server:\n\n```\nappium --use-plugins=universal-xml\n```\n\n# @appium/universal-xml-plugin > ## Examples\n\n# @appium/universal-xml-plugin > ## Examples > ### Node names\n\n|iOS|Android|Transformed|\n|-|-|-|\n|`XCUIElementTypeButton`|`android.widget.Button`|`Button`|\n|`XCUIElementTypeAlert`|`android.widget.Toast`|`Alert`|\n|`XCUIElementTypeSwitch`|`android.widget.Switch`|`SwitchInput`|\n\nSee [the mapping file](./lib/node-map.js) for a full list of node name translations. Any names not\nspecified are left as-is.\n\n# @appium/universal-xml-plugin > ## Examples > ### Attribute names\n\n|iOS|Android|Transformed|\n|-|-|-|\n|`name`|`content-desc`|`axId`|\n|`label`|`text`|`text`|\n|`visible`|`displayed`|`visible`|\n\nNote that this plugin also removes a few attributes from the transformed XML. See\n[the mapping file](./lib/attr-map.js) for a full list of attribute name translations and removed\nattributes. Any names not specified are left as-is.\n\n# @appium/universal-xml-plugin > ## License\n\nApache-2.0","metadata":{"headerPath":"# @appium/universal-xml-plugin","sectionCount":7,"filename":"README.md","relativePath":"appium/packages/universal-xml-plugin/README.md"}},{"pageContent":"# Appium's Renovate Configuration\n\n> Reusable [Renovate](https://www.mend.io) config for Appium and Appium-adjacent projects\n\n# Appium's Renovate Configuration > ## Usage\n\nModify your Renovate config file (`renovate.json`, etc.) to extend:\n\n```json\n\"github>appium/appium//renovate/default\"\n```\n\nFor example, a JSON config should contain:\n\n```json\n{\n \"extends\": [\n \"github>appium/appium//renovate/default\"\n ]\n}\n```\n\nIf you already have a top-level `extends`, then append this to the list.\n\n# Appium's Renovate Configuration > ## Notes\n\n> See the [Renovate docs](https://docs.renovatebot.com/) for more information on what does what.\n\n# Appium's Renovate Configuration > ## Why\n\nAppium-the-project has many repos--not just this one! We found ourselves duplicating most of this config across packages, so here's a reusable config.\n\nAppium extension authors--or anyone else--may use this config as well.\n\n# Appium's Renovate Configuration > ## Why > ### Presets in Use\n\n- `config:js-app` - everything gets pinned except peer deps (plus a bunch of other reasonable defaults)\n- `group:definitelyTyped` - Groups all `@types/*` packages into one PR\n- `workarounds:typesNodeVersioning` - `@types/node` tracks Node.js versions instead\n- `:automergeStableNonMajor` - Automatically merges \"patch\" and \"minor\" updates for semver stable (>=1.0.0) packages (assuming they pass CI)\n- `:automergeDigest` - Automatically merges \"digest\" updates (assuming they pass CI)\n- `:enableVulnerabilityAlerts` - For \"security\" purposes\n- `:rebaseStalePrs` - Renovate will automatically rebase its PRs\n- `:semanticCommits` - Renovate will use semantic commit messages\n- `:semanticCommitTypeAll(chore)` - Renovate's PRs have the `chore` prefix in its semantic commit message\n\n# Appium's Renovate Configuration > ## Why > ### Custom Rules\n\n- Do not upgrade to major versions of packages which have become ESM-only. Unfortunately this is an explicit deny-list.\n- Groups (groups updates into single PR):\n - ESLint-related and [@appium/eslint-config-appium-ts](https://github.com/appium/appium/tree/master/eslint-config-appium-ts)\n - [teen_process](https://github.com/appium/node-teen_process) and its DT types\n - Appium-scoped (`@appium`) packages. This applies to _other_ repos which depend on Appium, such as official drivers.\n\n> Note: The packages in the do-not-upgrade-majors list _may or may not be used_ by Appium; the intent is to not remove anything from this list (unless they start publishing CJS again).","metadata":{"headerPath":"# Appium's Renovate Configuration","sectionCount":6,"filename":"README.md","relativePath":"appium/renovate/README.md"}},{"pageContent":"# Appium's Renovate Configuration > ## Why > ### Additional Config\n\n- Uses the parent directory for the commit scope if applicable; otherwise uses `deps`. The parent directory is _typically_ only applicable in monorepos.\n\n# Appium's Renovate Configuration > ## License\n\nApache-2.0","metadata":{"headerPath":"# Appium's Renovate Configuration > ## Why > ### Additional Config","sectionCount":2,"filename":"README.md","relativePath":"appium/renovate/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver\n\n[![NPM version](http://img.shields.io/npm/v/appium-uiautomator2-driver.svg)](https://npmjs.org/package/appium-uiautomator2-driver)\n[![Downloads](http://img.shields.io/npm/dm/appium-uiautomator2-driver.svg)](https://npmjs.org/package/appium-uiautomator2-driver)\n\n[![Release](https://github.com/appium/appium-uiautomator2-driver/actions/workflows/publish.js.yml/badge.svg)](https://github.com/appium/appium-uiautomator2-driver/actions/workflows/publish.js.yml)\n\n\nAppium UiAutomator2 Driver is a test automation framework for Android devices. Appium UiAutomator2 Driver automates native, hybrid and mobile web apps, tested on emulators and real devices. Appium UiAutomator2 Driver is part of the [Appium](https://github.com/appium/appium) mobile test automation tool. The driver operates in scope of [W3C WebDriver protocol](https://www.w3.org/TR/webdriver/) with several custom extensions to cover operating-system specific scenarios.\n\nUiAutomator2 Driver proxies most of the commands to [UiAutomator2 server](https://github.com/appium/appium-uiautomator2-server), which uses Google's [UiAutomator](https://developer.android.com/training/testing/ui-automator) framework under the hood. Some commands are proxied directly to [appium-adb](https://github.com/appium/appium-adb) and other helpers built on top of Android platform tools.\n\n> [!IMPORTANT]\n> Since major version *5.0.0*, this driver is only compatible with Appium 3. Use the `appium driver install uiautomator2`\n> command to add it to your distribution.","metadata":{"headerPath":"# Appium UiAutomator2 Driver","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Requirements\n\nOn top of standard Appium requirements UiAutomator2 driver also expects the following prerequisites:\n\n- Windows, Linux and macOS are supported as hosts\n- [Android SDK Platform tools](https://developer.android.com/studio/releases/platform-tools) must be installed. [Android Studio IDE](https://developer.android.com/studio) also provides a convenient UI to install and manage the tools.\n- ANDROID_HOME or ANDROID_SDK_ROOT [environment variable](https://developer.android.com/studio/command-line/variables) must be set\n- Java JDK must be installed and [JAVA_HOME](https://www.baeldung.com/java-home-on-windows-7-8-10-mac-os-x-linux) environment variable must be set. Android SDK below API 30 requires Java 8. Android SDK 30 and above requires Java 9 or newer.\n- [Emulator](https://developer.android.com/studio/run/managing-avds) platform image must be installed if you plan to run your tests on it. [Android Studio IDE](https://developer.android.com/studio) also provides a convenient UI to install and manage emulators.\n- Real Android devices must have [USB debugging enabled](https://developer.android.com/studio/debug/dev-options) and should be visible as `online` in `adb devices -l` output.\n- Since driver version 6.0.0 the minimum supported version of Android API is 8/Oreo (API level 26).\nBefore version 6.0.0 the minimum supported version of Android API is 5 (API level 21).\n6.0 is recommended as version 5 has some known compatibility issues.\n\n# Appium UiAutomator2 Driver > ## Requirements > ### Doctor\n\nSince driver version 2.39.0 you can automate the validation for the most of the above\nrequirements as well as various optional ones needed by driver extensions by running the\n`appium driver doctor uiautomator2` server command.\n\n# Appium UiAutomator2 Driver > ## Capabilities","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Requirements","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### General\n\nCapability Name | Description\n--- | ---\nplatformName | Could be set to `android`. Appium itself is not strict about this capability value if `automationName` is provided, so feel free to assign it to any supported platform name if this is needed, for example, to make Selenium Grid working.\nappium:automationName | Must always be set to `uiautomator2`. Values of `automationName` are compared case-insensitively.\nappium:deviceName | The name of the device under test (actually, it is not used to select a device under test). Consider setting `udid` for real devices and `avd` for emulators instead\nappium:platformVersion | The platform version of an emulator or a real device. This capability is used for device autodetection if `udid` is not provided\nappium:udid | UDID of the device to be tested. Could be retrieved from `adb devices -l` output. If unset then the driver will try to use the first connected device. Always set this capability if you run parallel tests.\nappium:noReset | Prevents the device to be reset before the session startup if set to `true`. This means that the application under test is not going to be terminated neither its data cleaned. `false` by default\nappium:fullReset | Being set to `true` always enforces the application under test to be fully uninstalled before starting a new session. `false` by default\nappium:printPageSourceOnFindFailure | Enforces the server to dump the actual XML page source into the log if any error happens. `false` by default.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### General","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### Driver/Server\n\nCapability Name | Description\n--- | ---\nappium:systemPort | The number of the port on the host machine used for the UiAutomator2 server. By default the first free port from 8200..8299 range is selected. It is recommended to set this value if you are running [parallel tests](#parallel-tests) on the same machine.\nappium:skipServerInstallation | Skip the UiAutomator2 Server component installation on the device under test and all the related checks if set to `true`. This could help to speed up the session startup if you know for sure the correct server version is installed on the device. In case the server is not installed or an incorrect version of it is installed then you may get an unexpected error later. `false` by default\nappium:uiautomator2ServerLaunchTimeout | The maximum number of milliseconds to wait util UiAutomator2Server is listening on the device. `30000` ms by default\nappium:uiautomator2ServerInstallTimeout | The maximum number of milliseconds to wait util UiAutomator2Server is installed on the device. `20000` ms by default\nappium:uiautomator2ServerReadTimeout | The maximum number of milliseconds to wait for a HTTP response from UiAutomator2Server. Only values greater than zero are accepted. If the given value is too low then expect driver commands to fail with `timeout of Xms exceeded` error. `240000` ms by default\nappium:disableWindowAnimation | Whether to disable window animations when starting the instrumentation process. The animation scale will be restored automatically after the instrumentation process ends for API level 26 and higher. The animation scale could remain if the session ends unexpectedly for API level 25 and lower. `false` by default\nappium:skipDeviceInitialization | If set to `true` then device startup checks (whether it is ready and whether Settings app is installed) will be canceled on session creation. Could speed up the session creation if you know what you are doing. `false` by default","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### Driver/Server","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### App\n\nCapability Name | Description\n--- | ---\nappium:app | Full path to the application to be tested (the app must be located on the same machine where the server is running). Both `.apk` and `.apks` application extensions are supported. Could also be an URL to a remote location. If neither of the `app`, `appPackage` or `browserName` capabilities are provided then the driver starts from the Dashboard and expects the test knows what to do next. Do not provide both `app` and `browserName` capabilities at once.\nbrowserName | The name of the browser to run the test on. If this capability is provided then the driver will try to start the test in Web context mode (Native mode is applied by default). Read [Automating hybrid apps](#hybrid-mode) for more details. Usually equals to `chrome`.\nappium:appPackage | Application package identifier to be started. If not provided then UiAutomator2 will try to detect it automatically from the package provided by the `app` capability. Read [How To Troubleshoot Activities Startup](docs/activity-startup.md) for more details\nappium:appActivity | Main application activity identifier. If not provided then UiAutomator2 will try to detect it automatically from the package provided by the `app` capability. Read [How To Troubleshoot Activities Startup](docs/activity-startup.md) for more details\nappium:appWaitActivity | Identifier of the first activity that the application invokes. If not provided then equals to `appium:appActivity`. Read [How To Troubleshoot Activities Startup](docs/activity-startup.md) for more details\nappium:appWaitPackage | Identifier of the first package that is invoked first. If not provided then equals to `appium:appPackage`. Read [How To Troubleshoot Activities Startup](docs/activity-startup.md) for more details\nappium:appWaitDuration | Maximum amount of milliseconds to wait until the application under test is started (e. g. an activity returns the control to the caller). `20000` ms by default. Read [How To Troubleshoot Activities Startup](docs/activity-startup.md) for more details\nappium:androidInstallTimeout | Maximum amount of milliseconds to wait until the application under test is installed. `90000` ms by default\nappium:appWaitForLaunch | Whether to block until the app under test returns the control to the caller after its activity has been started by Activity Manager (`true`, the default value) or to continue the test without waiting for that (`false`).","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### App","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### App\n\nappium:intentCategory | Set an optional intent category to be applied when starting the given appActivity by [Activity Manager](https://developer.android.com/studio/command-line/adb#am). Defaults to `android.intent.category.LAUNCHER`. Please use [mobile:startActivity](#mobile-startactivity) in case you don't set an explicit value.\nappium:intentAction | Set an optional intent action to be applied when starting the given appActivity by [Activity Manager](https://developer.android.com/studio/command-line/adb#am). Dfaults to `android.intent.action.MAIN`. Please use [mobile:startActivity](#mobile-startactivity) in case you don't set an explicit value.\nappium:intentFlags | Set an optional intent flags to be applied when starting the given appActivity by [Activity Manager](https://developer.android.com/studio/command-line/adb#am). Defaults to `0x10200000` (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flags). Please use [mobile:startActivity](#mobile-startactivity) in case you don't set an explicit value.\nappium:optionalIntentArguments | Set an optional intent arguments to be applied when starting the given appActivity by [Activity Manager](https://developer.android.com/studio/command-line/adb#am)\nappium:dontStopAppOnReset | Set it to `true` if you don't want the application to be restarted if it was already running. If `appium:noReset` is falsy, then the app under test is going to be restarted if either this capability is falsy (the default behavior) or `appium:forceAppLaunch` is set to `true`. `false` by default\nappium:forceAppLaunch | Set it to `true` if you want the application under test to be always forcefully restarted on session startup even if `appium:noReset` is `true`, and the app was already running. If `noReset` is falsy, then the app under test is going to be restarted if either this capability set to `true` or `appium:dontStopAppOnReset` is falsy (the default behavior). `false` by default. Available since driver version 2.12\nappium:shouldTerminateApp | Set it to `true` if you want the application under test to be always terminated on session end even if `appium:noReset` is `true`. If `noReset` is falsy, then the app under test is going to be terminated if `appium:dontStopAppOnReset` is also falsy (the default behavior). `false` by default\nappium:autoLaunch | Whether to launch the application under test automatically (`true`, the default value) after a test starts","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### App","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### App\n\nappium:autoLaunch | Whether to launch the application under test automatically (`true`, the default value) after a test starts\nappium:autoGrantPermissions | Whether to grant all the requested application permissions automatically when a test starts(`true`). The targetSdkVersion in the application manifest must be greater or equal to 23 and the Android version on the device under test must be greater or equal to Android 6 (API level 23) to grant permissions. Applications whose targetSdkVersion is lower than or equal to 22 must be reinstalled to grant permissions, for example, by setting the `appium:fullReset` capability as `true` for Android 6+ devices. If your app needs some special security permissions, like access to notifications or media recording, consider using [mobile: changePermissions](#mobile-changepermissions) extension with `appops` target. `false` by default\nappium:otherApps | Allows to set one or more comma-separated paths to Android packages that are going to be installed along with the main application under test. This may be useful if the tested app has dependencies\nappium:uninstallOtherPackages | Allows to set one or more comma-separated package identifiers to be uninstalled from the device before a test starts\nappium:allowTestPackages | If set to `true` then it would be possible to use packages built with the test flag for the automated testing (literally adds `-t` flag to the `adb install` command). `false` by default\nappium:remoteAppsCacheLimit | Sets the maximum amount of application packages to be cached on the device under test. This is needed for devices that don't support streamed installs (Android 7 and below), because ADB must push app packages to the device first in order to install them, which takes some time. Setting this capability to zero disables apps caching. `10` by default.\nappium:enforceAppInstall | If set to `true` then the application under test is always reinstalled even if a newer version of it already exists on the device under test. This capability has no effect if `appium:noReset` is set to `true`. `false` by default.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### App","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### App Localization\n\nCapability Name | Description\n--- | ---\nappium:localeScript | Canonical name of the locale to be set for the app under test, for example `Hans` in `zh-Hans-CN`. See https://developer.android.com/reference/java/util/Locale.html for more details.\nappium:language | Name of the language to extract application strings for. Strings are extracted for the current system language by default. Also sets the language for the app under test. See https://developer.android.com/reference/java/util/Locale.html for more details. If `language` is provided then `locale` is also required to be set. The combination of both capability values must be a known locale and should be present in the list of available locales returned by the ICU's [getAvailableULocales()](https://unicode-org.github.io/icu/userguide/locale/#usage-retrieving-locales) method. The full list of supported locales is also dumped into the logcat output on failure. Example: `en`, `ja`\nappium:locale | Sets the locale for the app under test. See https://developer.android.com/reference/java/util/Locale.html for more details. If `locale` is provided then `language` is also required to be set. The combination of both capability values must be a known locale and should be present in the list of available locales returned by the ICU's [getAvailableULocales()](https://unicode-org.github.io/icu/userguide/locale/#usage-retrieving-locales) method. The full list of supported locales is also dumped into the logcat output on failure. Example: `US`, `JP`","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### App Localization","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### ADB\n\nCapability Name | Description\n--- | ---\nappium:adbPort | Number of the port on the host machine where ADB is running. `5037` by default\nappium:remoteAdbHost | Address of the host where ADB is running (the value of `-H` ADB command line option). Unset by default\nappium:adbExecTimeout | Maximum number of milliseconds to wait until single ADB command is executed. `20000` ms by default\nappium:clearDeviceLogsOnStart | If set to `true` then UiAutomator2 deletes all the existing logs in the device buffer before starting a new test\nappium:buildToolsVersion | The version of Android build tools to use. By default UiAutomator2 driver uses the most recent version of build tools installed on the machine, but sometimes it might be necessary to give it a hint (let say if there is a known bug in the most recent tools version). Example: `28.0.3`\nappium:skipLogcatCapture | Being set to `true` disables automatic logcat output collection during the test run. `false` by default\nappium:suppressKillServer | Being set to `true` prevents the driver from ever killing the ADB server explicitly. Could be useful if ADB is connected wirelessly. `false` by default\nappium:ignoreHiddenApiPolicyError | Being set to `true` ignores a failure while changing hidden API access policies to [enable access to non-SDK interfaces](https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces#how_can_i_enable_access_to_non-sdk_interfaces). Could be useful on some devices, where access to these policies has been locked by its vendor. `false` by default.\nappium:hideKeyboard | Being set to `true` hides the on-screen keyboard while the session is running. Use it instead of the legacy `appium:unicodeKeyboard` one (which will be dropped in the future). This effect is achieved by assigning a custom \"artificial\" [input method](https://developer.android.com/develop/ui/views/touch-and-input/creating-input-method). Only use this feature for special/exploratory cases as it violates the way your application under test is normally interacted with by a human. Setting this capability explicitly to `false` enforces `adb shell ime reset` call on session startup, which resets the currently selected/enabled IMEs to the default ones as if the device is initially booted with the current locale. `undefined` by default.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### ADB","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### ADB\n\nappium:mockLocationApp | Sets the package identifier of the app, which is used as a system mock location provider since Appium 1.18.0+. This capability has no effect on emulators. If the value is set to `null` or an empty string, then the driver will reset the mocked location provider, e.g. the location won't be mocked anymore. Defaults to Appium Setting package identifier (`io.appium.settings`). Termination of a mock location provider application resets the mocked location data.\nappium:logcatFormat | The log print format, where `format` is one of: `brief` `process` `tag` `thread` `raw` `time` `threadtime` `long`. `threadtime` is the default value.\nappium:logcatFilterSpecs | Series of `tag[:priority]` where `tag` is a log component tag (or * for all) and priority is: `V Verbose`, `D Debug`, `I Info`, `W Warn`, `E Error`, `F Fatal`, `S Silent (supress all output)`. '*' means '*:d' and `tag` by itself means `tag:v`. If not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS. If no filterspec is found, filter defaults to '*:I'.\nappium:allowDelayAdb | Being set to `false` prevents emulator to use `-delay-adb` feature to detect its startup. See https://github.com/appium/appium/issues/14773 for more details.\nappium:adbListenAllNetwork | Being set to `true` adds `-a` ADB command line global option. Requires `uiautomator2:adb_listen_all_network` [security feature](https://github.com/appium/appium/blob/master/packages/appium/docs/en/guides/security.md) to be enabled. Unset by default. Available since driver version 6.7.0.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### ADB","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### Emulator (Android Virtual Device)\n\nCapability Name | Description\n--- | ---\nappium:avd | The name of Android emulator to run the test on. The names of currently installed emulators could be listed using `avdmanager list avd` command. If the emulator with the given name is not running then it is going to be launched on automated session startup.\nappium:avdLaunchTimeout | Maximum number of milliseconds to wait until Android Emulator is started. `60000` ms by default\nappium:avdReadyTimeout | Maximum number of milliseconds to wait until Android Emulator is fully booted and is ready for usage. `60000` ms by default\nappium:avdArgs | Either a string or an array of emulator [command line arguments](https://developer.android.com/studio/run/emulator-commandline). If arguments contain the `-wipe-data` one then the emulator is going to be killed on automated session startup in order to wipe its data.\nappium:avdEnv | Mapping of emulator [environment variables](https://developer.android.com/studio/command-line/variables).\nappium:networkSpeed | Sets the desired network speed limit for the emulator. It is only applied if the emulator is not running before the test starts. See emulator [command line arguments](https://developer.android.com/studio/run/emulator-commandline) description for more details.\nappium:gpsEnabled | Sets whether to enable (`true`) or disable (`false`) GPS service in the Emulator. Unset by default, which means to not change the current value\nappium:isHeadless | If set to `true` then emulator starts in headless mode (e.g. no UI is shown). It is only applied if the emulator is not running before the test starts. `false` by default.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### Emulator (Android Virtual Device)","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### Emulator (Android Virtual Device)\n\nappium:isHeadless | If set to `true` then emulator starts in headless mode (e.g. no UI is shown). It is only applied if the emulator is not running before the test starts. `false` by default.\nappium:injectedImageProperties | Allows adjusting of injected image properties, like size, position or rotation. The image itself is expected to be injected by [mobile: injectEmulatorCameraImage](#mobile-injectemulatorcameraimage) extension. It is also mandatory to provide this capability if you are going to use the injection feature on a newly created/resetted emulator as it __enforces emulator restart__, so it could properly reload the modified image properties. The value itself is a map, where possible keys are `size`, `position` and `rotation`. All of them are optional. If any of values is not provided then the following defaults are used: `{size: {scaleX: 1, scaleY: 1}, position: {x: 0, y: 0, z: -1.5}, rotation: {x: 0, y: 0, z: 0}}`. The `size` value contains scale multipliers for X and Y axes. The `position` contains normalized coefficients for X/Y/Z axes, where `0` means it should be centered in the viewport. Values in the `rotation` are measured in degrees respectively for X, Y and Z axis. The capability is available since the driver version 3.6.0.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### Emulator (Android Virtual Device)","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### App Signing\n\nCapability Name | Description\n--- | ---\nappium:useKeystore | Whether to use a custom keystore to sign the app under test. `false` by default, which means apps are always signed with the default Appium debug certificate (unless canceled by `noSign` capability). This capability is used in combination with `keystorePath`, `keystorePassword`, `keyAlias` and `keyPassword` capabilities.\nappium:keystorePath | The full path to the keystore file on the server filesystem. This capability is used in combination with `useKeystore`, `keystorePath`, `keystorePassword`, `keyAlias` and `keyPassword` capabilities. Unset by default\nappium:keystorePassword | The password to the keystore file provided in `keystorePath` capability. This capability is used in combination with `useKeystore`, `keystorePath`, `keystorePassword`, `keyAlias` and `keyPassword` capabilities. Unset by default\nappium:keyAlias | The alias of the key in the keystore file provided in `keystorePath` capability. This capability is used in combination with `useKeystore`, `keystorePath`, `keystorePassword`, `keyAlias` and `keyPassword` capabilities. Unset by default\nappium:keyPassword | The password of the key in the keystore file provided in `keystorePath` capability. This capability is used in combination with `useKeystore`, `keystorePath`, `keystorePassword`, `keyAlias` and `keyPassword` capabilities. Unset by default\nappium:noSign | Set it to `true` in order to skip application signing. By default all apps are always signed with the default Appium debug signature if they don't have any. This capability cancels all the signing checks and makes the driver to use the application package as is. This capability does not affect `.apks` packages as these are expected to be already signed.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### App Signing","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### Device Locking\n\nCapability Name | Description\n--- | ---\nappium:skipUnlock | Whether to skip the check for lock screen presence (`true`). The default driver behaviour is to verify the presence of the screen lock (e.g. 'false' value of the capability) before starting the test and to unlock that (which sometimes may be unstable). Note, that this operation takes some time, so it is highly recommended to set this capability to `true` and disable screen locking on device(s) under test. Read the [Unlock tutorial](./docs/unlock/main.md) for more details.\nappium:unlockType | Set one of the possible types of Android lock screens to unlock. Read the [Unlock tutorial](./docs/unlock/main.md) for more details.\nappium:unlockKey | Allows to set an unlock key. Read the [Unlock tutorial](./docs/unlock/main.md) for more details.\nappium:unlockStrategy | Either 'locksettings' (default) or 'uiautomator'. Read the [Unlock tutorial](./docs/unlock/main.md) for more details.\nappium:unlockSuccessTimeout | Maximum number of milliseconds to wait until the device is unlocked. `2000` ms by default. Read the [Unlock tutorial](./docs/unlock/main.md) for more details.\n\n# Appium UiAutomator2 Driver > ## Capabilities > ### MJPEG\n\nCapability Name | Description\n--- | ---\nappium:mjpegServerPort | The number of the port on the host machine that UiAutomator2 server starts the MJPEG server on. If not provided then the screenshots broadcasting service on the remote device does not get exposed to a local port (e.g. no adb port forwarding is happening)\nappium:mjpegScreenshotUrl | The URL of a service that provides realtime device screenshots in MJPEG format. If provided then the actual command to retrieve a screenshot will be requesting pictures from this service rather than directly from the server","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### Device Locking","sectionCount":2,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### Web Context\n\nCapability Name | Description\n--- | ---\nappium:autoWebview | If set to `true` then UiAutomator2 driver will try to switch to the web view with name `WEBVIEW_ + appium:appPackage` after the session is started. For example, if `appium:appPackage` capability is set to `com.mypackage` then `WEBVIEW_com.mypackage` will be used. `false` by default.\nappium:autoWebviewName | Set the name of webview context in which UiAutomator2 driver will try to switch if `autoWebview` capability is set to `true` (available since driver version 2.9.1). Has priority over using the `appium:appPackage` value in webview name. For example, if `appium:autoWebviewName` capability is set to `myWebviewName` then `WEBVIEW_myWebviewName` will be used. Unset by default.\nappium:autoWebviewTimeout | Set the maximum number of milliseconds to wait until a web view is available if `autoWebview` capability is set to `true`. `2000` ms by default.\nappium:webviewDevtoolsPort | The local port number to use for devtools communication. By default the first free port from 10900..11000 range is selected. Consider setting the custom value if you are running parallel tests.\nappium:ensureWebviewsHavePages | Whether to skip web views that have no pages from being shown in `getContexts` output. The driver uses devtools connection to retrieve the information about existing pages. `true` by default since Appium 1.19.0, `false` if lower than 1.19.0.\nappium:enableWebviewDetailsCollection | Whether to retrieve extended web views information using devtools protocol. Enabling this capability helps to detect the necessary chromedriver version more precisely. `true` by default since Appium 1.22.0, `false` if lower than 1.22.0.\nappium:chromedriverPort | The port number to use for Chromedriver communication. Any free port number is selected by default if unset.\nappium:chromedriverPorts | Array of possible port numbers to assign for Chromedriver communication. If none of the port in this array is free then an error is thrown.\nappium:chromedriverArgs | Array of chromedriver command line arguments, listed with `chromedriver --help`. Note that not all command line arguments available for the desktop browser are also available for the mobile one.\nappium:chromedriverExecutable | Full path to the chromedriver executable on the server file system.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### Web Context","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### Web Context\n\nappium:chromedriverExecutable | Full path to the chromedriver executable on the server file system.\nappium:chromedriverExecutableDir | Full path to the folder where chromedriver executables are located. This folder is used then to store the downloaded chromedriver executables if automatic download is enabled. Read [Automatic Chromedriver Discovery article](#automatic-discovery-of-compatible-chromedriver) for more details.\nappium:chromedriverChromeMappingFile | Full path to the chromedrivers mapping file. This file is used to statically map webview/browser versions to the chromedriver versions that are capable of automating them. Read [Automatic Chromedriver Discovery article](#automatic-discovery-of-compatible-chromedriver) for more details.\nappium:chromedriverUseSystemExecutable | Set it to `true` in order to enforce the usage of chromedriver, which gets downloaded by Appium automatically upon installation. This driver might not be compatible with the destination browser or a web view. `false` by default.\nappium:chromedriverDisableBuildCheck | Being set to `true` disables the compatibility validation between the current chromedriver and the destination browser/web view. Use it with care.\nappium:recreateChromeDriverSessions | If this capability is set to `true` then chromedriver session is always going to be killed and then recreated instead of just suspending it on context switching. `false` by default\nappium:nativeWebScreenshot | Whether to use screenshoting endpoint provided by UiAutomator framework (`true`) rather than the one provided by chromedriver (`false`, the default value). Use it when you experience issues with the latter.\nappium:extractChromeAndroidPackageFromContextName | If set to `true`, tell chromedriver to attach to the android package we have associated with the context name, rather than the package of the application under test. `false` by default.\nappium:showChromedriverLog | If set to `true` then all the output from chromedriver binary will be forwarded to the Appium server log. `false` by default.\npageLoadStrategy | One of the available page load strategies. See https://www.w3.org/TR/webdriver/#capabilities\nappium:chromeOptions | A mapping, that allows to customize chromedriver options. See https://chromedriver.chromium.org/capabilities for the list of available entries.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### Web Context","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### Web Context\n\nappium:chromeOptions | A mapping, that allows to customize chromedriver options. See https://chromedriver.chromium.org/capabilities for the list of available entries.\nappium:chromeLoggingPrefs | Chrome logging preferences mapping. Basically the same as [goog:loggingPrefs](https://newbedev.com/getting-console-log-output-from-chrome-with-selenium-python-api-bindings). It is set to `{\"browser\": \"ALL\"}` by default.\nappium:chromedriverForwardBiDi | Being set to `true` enables automated forwarding of chromedriver BiDi web socket to UIA2 driver web socket. This allows to send browser-specific BiDi commands being in a web view context. The web socket connection is terminated as soon as the session context is changed (by default all [BiDi commands](./docs/bidi.md) are handled by the UIA2 driver). It is required that session capabilities have the `webDriverUrl` capability set to `true`. Also note, that older chromedrivers may not support BiDi specification fully, or may not support it at all.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### Web Context","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Capabilities > ### Other\n\nCapability Name | Description\n--- | ---\nappium:disableSuppressAccessibilityService | Being set to `true` tells the instrumentation process to not suppress accessibility services during the automated test. This may be useful if your automated test needs these services. `false` by default\nappium:userProfile | Integer identifier of a [user profile](https://source.android.com/devices/tech/admin/multi-user). By default the app under test is installed for the currently active user, but in case it is necessary to test how the app performs while being installed for a user profile, which is different from the current one, then this capability may come in handy.\nappium:newCommandTimeout | How long (in seconds) the driver should wait for a new command from the client before assuming the client has stopped sending requests. After the timeout the session is going to be deleted. `60` seconds by default. Setting it to zero disables the timer.\nappium:skipLogcatCapture | Skips to start capturing logs such as logcat. It may improve network performance. Log-related commands won't work if the capability is enabled. Defaults to `false`.\nappium:timeZone | Overrides the current device's time zone since the driver version 3.1.0. This change is preserved until the next override. The time zone identifier must be a valid name from the list of [available time zone identifiers](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones), for example `Europe/Kyiv`","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Capabilities > ### Other","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Element Attributes\n\nUiAutomator2 driver supports the following element attributes:","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Element Attributes","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Element Attributes\n\nName | Description | Example\n--- | --- | ---\ncheckable | Whether the element is checkable or not | 'true'\nchecked | Whether the element is checked. Always `false` if the element is not checkable | 'false'\nclass or className | The full name of the element's class. Could be `null` for some elements | 'android.view.View'\nclickable | Whether the element could be clicked | 'false'\ncontent-desc or contentDescription | The content-description attribute of the accessible element | 'foo'\nenabled | Whether the element could be clicked | 'true'\nfocusable | Whether the element could be focused | 'true'\nfocused | Whether the element could is focused. Always `false` if the element is not focusable | 'false'\nlong-clickable or longClickable | Whether the element accepts long clicks | 'false'\npackage | Identifier of the package the element belongs to | 'com.mycompany'\npassword | Whether the element is a password input field | 'true'\nresource-id or resourceId | Element's resource identifier. Could be `null` | 'com.mycompany:id/resId'\nscrollable | Whether the element is scrollable | 'true'\nselection-start | Contains the index of the char where the selection starts. Could be `null` if the element provides no range info | '5'\nselection-end | Contains the index of the char where the selection ends. Could be `null` if the element provides no range info | '8'\nselected | Whether the element is selected | 'false'\ntext or name | The element's text. It never equals to null | 'my text'\nhint | Element's hint text. On Android versions below Oreo it always equals to `null`. | 'my hint text'\nbounds | The element's visible frame (`[left, top][right, bottom]`) | `[0,0][100,100]`\ndisplayed | Whether the element is visible to the user | 'true'\ncontentSize | The dimensions of the element's content area | `{\"left\": 0, \"top\":0, \"width\": 100, \"height\": 100, \"scrollableOffset\": 10, \"touchPadding\": 0}`\nextras | The result of [getExtras](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#getExtras()). The value includes all key-value pairs as `key=value` separated by a semicolon (`;`). If the value is empty, then only key part ending with the equal sign will be present. Available only if `includeExtrasInPageSource` setting is turned on. | Part of extras in chrome browser:<br> `AccessibilityNodeInfo.roleDescription=;`<br>`AccessibilityNodeInfo.chromeRole=rootWebArea;`<br> `ACTION_ARGUMENT_HTML_ELEMENT_STRING_VALUES=`<br> `ARTICLE,BLOCKQUOTE,BUTTON,CHECKBOX`","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Element Attributes","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Element Attributes\n\na11y-important | Whether the element originates from a view considered important for accessibility. Available for API 24+ | 'true'\nscreen-reader-focusable | Whether the element is explicitly marked as a focusable unit by a screen reader. Available for API 28+ | 'true'\ninput-type | Bitmask, input type of the editable text element, defined by [InputType](https://developer.android.com/reference/android/text/InputType). Available only for text input fields. | '1'\ndrawing-order | The drawing position of the view corresponding to this element relative to its siblings. Available for API 24+ | '3'\nshowing-hint | Whether the element's text represents a hint for the user to enter text. Available for API 26+ | 'true'\ntext-entry-key | Whether the element represents a text entry key that is part of a keyboard or keypad. Available for API 29+ | 'true'\nmultiline | If the element is a multi line editable text. Available only for text input fields. | 'true'\ndismissable | If the element can be dismissed | 'true'\na11y-focused | Whether this element is accessibility focused | 'true'\nheading | Whether element represents a heading. Available for API 28+ | 'true'\nlive-region | Bitmask, live region mode value for the element, like '1' for [ACCESSIBILITY_LIVE_REGION_POLITE](https://developer.android.com/reference/android/view/View#ACCESSIBILITY_LIVE_REGION_POLITE) | '1'\ncontext-clickable | Whether this element is context clickable. Available for API 23+ | 'true'\nmax-text-length | The maximum text length for the editable text element. Available only for text input fields. | '300'\ncontent-invalid | If the content of this element is invalid. For example, a date is not well-formed. | 'true'\nerror | The error text of the element. | 'text string'\npane-title | Title of the pane represented by this element. Available for API 28+ | 'text string'\nactions | The comma-separated id names of the available accessibility actions for the element from [getActionList](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#getActionList()). Available only if `includeA11yActionsInPageSource` setting is turned on. | 'ACTION_FOCUS,ACTION_SELECT,ACTION_CLEAR_SELECTION,ACTION_CLICK,ACTION_ACCESSIBILITY_FOCUS,ACTION_NEXT_AT_MOVEMENT_GRANULARITY,ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,ACTION_SET_SELECTION,ACTION_SHOW_ON_SCREEN'","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Element Attributes","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Element Attributes\n\ntooltip-text | The result of [getTooltipText](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#getTooltipText()). Could be `null`, available for API 28+ | 'Paste'\ntext-has-clickable-span | Indicates whether the `TextView` content contains `ClickableSpan` or `URLSpan` elements, `null` in all other cases. | 'true'\nwindow-id | The integer identifier of the [accessbility window](https://developer.android.com/reference/android/view/accessibility/AccessibilityWindowInfo) this element belongs to. In some rare cases, it may not be present if the window identifier cannot be determined. | 123","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Element Attributes","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Element Location\n\nUiAutomator2 driver supports the following location strategies:\n\nName | Description | Speed Ranking | Example\n--- | --- | --- | ---\nid | This strategy is mapped to the native UiAutomator's `By.res` [locator](https://developer.android.com/reference/androidx/test/uiautomator/BySelector#res(java.lang.String)) (exact match of element's resource name). Package identifier prefix is added automatically if unset and is equal to the identifier of the current application under test. | `⭐⭐⭐⭐⭐` | 'com.mycompany:id/resourceId'\naccessibilityId | This strategy is mapped to the native UiAutomator's `By.desc` [locator](https://developer.android.com/reference/androidx/test/uiautomator/BySelector#desc(java.lang.String)) (exact match of element's content description). In applications written using [ReactNative](https://reactnative.dev/) framework this attribute reflects the value of the `accessibilityLabel` property. | `⭐⭐⭐⭐⭐` | 'my description'\nclassName | This strategy is mapped to the native UiAutomator's `By.clazz` [locator](https://developer.android.com/reference/androidx/test/uiautomator/BySelector#clazz(java.lang.String)) (exact match of element's class). | `⭐⭐⭐⭐⭐` | 'android.view.View'\n-android uiautomator | This strategy is mapped to the native UiAutomator's `UiSelector` [locator](https://developer.android.com/reference/androidx/test/uiautomator/UiSelector)). It is even possible to perform some advanced operations, like scrolling, with this locator type. Check [Guide on UiAutomator Locator Types](docs/uiautomator-uiselector.md) | `⭐⭐⭐⭐` | new UiScrollable(new UiSelector().resourceId(\\\"android:id/list\\\")).scrollIntoView(new UiSelector().text(\\\"Radio Group\\\"))\nxpath | For elements lookup Xpath strategy the driver uses the same XML tree that is generated by page source API. Only Xpath 1.0 is supported for appium-uiatomator2-server versions below 4.25.0. All server versions starting from 4.25.0 support both Xpath 1.0 and 2.0 | `⭐⭐⭐` | By.xpath(\"//android.view.View[@text=\\\"Regular\\\" and @checkable=\\\"true\\\"]\")\n\n> [!NOTE] For testing multi-window applications, see the [Multi-Window Testing Guide](docs/android-multiwindow.md).","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Element Location","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Element Location\n\n> [!NOTE] For testing multi-window applications, see the [Multi-Window Testing Guide](docs/android-multiwindow.md).\n\n> [!WARNING]\n> Google is going to [deprecate](https://developer.android.com/training/testing/other-components/ui-automator-legacy#ui-automator)\n> and remove `UiCollection`, `UiObject`, `UiScrollable`, and `UiSelector` support from the UiAutomator framework.\n> This will render all `-android uiautomator`-based locators invalid, so please keep it in mind while\n> using them or plan to use them in the future.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Element Location","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## BiDi Protocol Support\n\nUIAutomator2 driver has partial support of the [BiDi Protocol](https://w3c.github.io/webdriver-bidi/) since version 3.7.10. Check the [Supported BiDi Commands And Events](./docs/bidi.md) document for more details.\n\n# Appium UiAutomator2 Driver > ## Parallel Tests\n\nIt is possible to execute tests in parallel using UiAutomator2 driver.\nAppium allows to do this on per-process (multiple server processes running on different ports managing single session)\nor per-request basis (single server process managing multiple sessions, more preferable, uses less resources and ensures better control over running sessions).\n\n_Note_: If you are not going to run your tests in parallel then consider enabling the `--session-override` Appium server argument.\nIt forces the server to close all pending sessions before a new one could be opened,\nwhich allows you to avoid possible issues with such sessions silently running/expiring in the background.\n\n# Appium UiAutomator2 Driver > ## Parallel Tests > ### Important Real Device Capabilities\n\n- `udid`: The unique device id.\n- `systemPort`: Set a unique system port number for each parallel session. Otherwise you might get a port conflict such as in [this issue](https://github.com/appium/appium/issues/7745).\n- `chromedriverPort`: The unique chromedriver port if testing web views or Chrome.\n- `mjpegServerPort`: Set a unique MJPEG server port for each parallel session if you are going to record a video.\n\n# Appium UiAutomator2 Driver > ## Parallel Tests > ### Important Emulator Capabilities\n\n- `avd`: The unique emulator name.\n- `systemPort`: Set a unique system port number for each parallel session.\n- `chromedriverPort`: The unique chromedriver port (if testing web views or Chrome).\n- `mjpegServerPort`: Set a unique MJPEG server port for each parallel session if you are going to record a video.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## BiDi Protocol Support","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Settings API\n\nUiAutomator2 driver supports Appium [Settings API](https://appium.io/docs/en/latest/guides/settings/).\nAlong with the common settings the following driver-specific settings are currently available:","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Settings API","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Settings API\n\nName | Type | Description\n--- | --- | ---\nactionAcknowledgmentTimeout | long | Maximum number of milliseconds to wait for an acknowledgment of generic uiautomator actions, such as clicks, text setting, and menu presses. The acknowledgment is an [AccessibilityEvent](http://developer.android.com/reference/android/view/accessibility/AccessibilityEvent.html) corresponding to an action, that lets the framework determine if the action was successful. Generally, this timeout should not be modified. `3000` ms by default\nallowInvisibleElements | boolean | Whether to include elements that are not visible to the user (e. g. whose `displayed` attribute is `false`) to the XML source tree. `false` by default\nignoreUnimportantViews | boolean | Enables or disables layout hierarchy compression. If compression is enabled, the layout hierarchy derived from the Acessibility framework will only contain nodes that are important for uiautomator testing. Any unnecessary surrounding layout nodes that make viewing and searching the hierarchy inefficient are removed. `false` by default\nelementResponseAttributes | string | Comma-separated list of element attribute names to be included into findElement response. By default only element UUID is present there, but it is also possible to add the following items: `name`, `text`, `rect`, `enabled`, `displayed`, `selected`, `attribute/<element_attribute_name>`. It is required that `shouldUseCompactResponses` setting is set to `false` in order for this one to apply.\nenableMultiWindows | boolean | Whether to include all windows that the user can interact with (for example an on-screen keyboard) while building the XML page source (`true`). By default it is `false` and only the single active application window is included to the page source. See the [Multi-Window Testing Guide](docs/android-multiwindow.md) for detailed information.\nenableTopmostWindowFromActivePackage | boolean | Whether to limit the window with the highest Z-order from the active package for interactions and page source retrieval. By default it is `false` and the active application window, which may not necessarily have this order, is included to the page source. See the [Multi-Window Testing Guide](docs/android-multiwindow.md) for detailed information.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Settings API","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Settings API\n\nenableNotificationListener | boolean | Whether to enable (`true`) toast notifications listener to listen for new toast notifications. By default this listener is enabled and UiAutomator2 server includes the text of toast messages to the generated XML page source, but not for longer than `3500` ms after the corresponding notification expires.\nkeyInjectionDelay | long | Delay in milliseconds between key presses when injecting text input. 0 ms by default\nscrollAcknowledgmentTimeout | long | Timeout for waiting for an acknowledgement of an uiautomator scroll swipe action. The acknowledgment is an [AccessibilityEvent](http://developer.android.com/reference/android/view/accessibility/AccessibilityEvent.html), corresponding to the scroll action, that lets the framework determine if the scroll action was successful. Generally, this timeout should not be modified. `200` ms by default\nshouldUseCompactResponses | boolean | Used in combination with `elementResponseAttributes` setting. If set to `false` then the findElement response is going to include the items enumerated in `elementResponseAttributes` setting. `true` by default\nwaitForIdleTimeout | long | Timeout used for waiting for the user interface to go into an idle state. By default, all core uiautomator objects except UiDevice will perform this wait before starting to search for the widget specified by the object's locator. Once the idle state is detected or the timeout elapses (whichever occurs first), the object will start to wait for the selector to find a match. Consider lowering the value of this setting if you experience long delays while interacting with accessibility elements in your test. `10000` ms by default.\nwaitForSelectorTimeout | long | Timeout for waiting for a widget to become visible in the user interface so that it can be matched by a selector. Because user interface content is dynamic, sometimes a widget may not be visible immediately and won't be detected by a selector. This timeout allows the uiautomator framework to wait for a match to be found, up until the timeout elapses. This timeout is only applied to `android uiautomator` location strategy. `10000` ms by default","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Settings API","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Settings API\n\nnormalizeTagNames | boolean | Being set to `true` applies unicode-to-ascii normalization of element class names used as tag names in the page source XML document. This is necessary if the application under test has some Unicode class names, which cannot be used as XML tag names by default due to known bugs in Android's XML DOM parser implementation. `false` by default\nshutdownOnPowerDisconnect | boolean | Whether to shutdown the server if the device under test is disconnected from a power source (e. g. stays on battery power). `true` by default.\nsimpleBoundsCalculation | boolean | Whether to calculate element bounds as absolute values (`true`) or check if the element is covered by other elements and thus partially hidden (`false`, the default behaviour). Setting this setting to `true` helps to improve the performance of XML page source generation, but decreases bounds preciseness. Use with care.\ntrackScrollEvents | boolean | Whether to apply scroll events tracking (`true`, the default value), so the server could calculate the value of `contentSize` attribute. Having this setting enabled may add delays to all scrolling actions.\nwakeLockTimeout | long | The timeout in milliseconds of wake lock that UiAutomator2 server acquires by default to prevent the device under test going to sleep while an automated test is running. By default the server acquires the lock for 24 hours. Setting this value to zero forces the server to release the wake lock.\nserverPort | int | The number of the port on the remote device to start UiAutomator2 server on. Do not mix this with `systemPort`, which is acquired on the host machine. Must be in range 1024..65535. `6790` by default\nmjpegServerPort | int | The number of the port on the remote device to start MJPEG screenshots broadcaster on. Must be in range 1024..65535. `7810` by default\nmjpegServerFramerate | int | The maximum count of screenshots per second taken by the MJPEG screenshots broadcaster. Must be in range 1..60. `10` by default\nmjpegScalingFactor | int | The percentage value used to apply downscaling on the screenshots generated by the MJPEG screenshots broadcaster. Must be in range 1..100. `50` is by default, which means that screenshots are downscaled to the half of their original size keeping their original proportions.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Settings API","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Settings API\n\nmjpegServerScreenshotQuality | int | The percentage value used to apply lossy JPEG compression on the screenshots generated by the MJPEG screenshots broadcaster. Must be in range 1..100. `50` is by default, which means that screenshots are compressed to the half of their original quality.\nmjpegBilinearFiltering | boolean | Controls whether (`true`) or not (`false`, the default value) to apply bilinear filtering to MJPEG screenshots broadcaster resize algorithm. Enabling this flag may improve the quality of the resulting scaled bitmap, but may introduce a small performance hit.\nuseResourcesForOrientationDetection | boolean | Defines the strategy used by UiAutomator2 server to detect the original device orientation. By default (`false` value) the server uses device rotation value for this purpose. Although, this approach may not work for some devices and a portrait orientation may erroneously be detected as the landscape one (and vice versa). In such case it makes sense to play with this setting.\nenforceXPath1 | boolean | Since UiAutomator2 driver version `4.25.0` XPath2 is set as the default and the recommended interpreter for the corresponding element locators. This interpreter is based on [Psychopath XPath2](https://wiki.eclipse.org/PsychoPathXPathProcessor) implementation, which is now a part of the Eclipse foundation. In most of the cases XPath1 locators are also valid XPath2 locators, so there should be no issues while locating elements. Although, since the XPath2 standard is much more advanced in comparison to the previous version, some [issues](https://github.com/appium/appium/issues/16142) are possible for more sophisticated locators, which cannot be fixed easily, as we depend on the third-party library mentioned above. Then try to workaround such issues by enforcing XPath1 usage (whose implementation is a part of the Android platform itself) and assigning this setting to `true`. Note, this setting is actually applied at the time when the element lookup by XPath is executed, so you could switch it on or off whenever needed throughout your automated testing session.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Settings API","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Settings API\n\nlimitXPathContextScope | boolean | Due to historical reasons UiAutomator2 driver limits scopes of element context-based searches to the parent element. This means a request like `findElement(By.xpath, \"//root\").findElement(By.xpath, \"./..\")` would always fail, because the driver only collects descendants of the `root` element for the destination XML source. The `limitXPathContextScope` setting being set to `false` changes that default behavior, so the collected page source includes the whole page source XML where `root` node is set as the search context. With that setting disabled the search query above should not fail anymore. Although, you must still be careful while building XPath requests for context-based searches with the `limitXPathContextScope` setting set to `false`. A request like `findElement(By.xpath, \"//root\").findElement(By.xpath, \"//element\")` would ignore the current context and search for `element` trough the whole page source. Use `.` notation to correct that behavior and only find `element` nodes which are descendants of the `root` node: `findElement(By.xpath, \"//root\").findElement(By.xpath, \".//element\")`.\ndisableIdLocatorAutocompletion | boolean | According to internal Android standards it is expected that each resource identifier is prefixed with `<packageName>:id/` string. This should guarantee uniqueness of each identifier. Although some application development frameworks ignore this rule and don't add such prefix automatically or, rather, let it up to the developer to decide how to represent their application identifiers. For example, [testTag modifier attribute in the Jetpack Compose](https://developer.android.com/reference/kotlin/androidx/compose/ui/platform/package-summary#(androidx.compose.ui.Modifier).testTag(kotlin.String)) with [testTagsAsResourceId](https://developer.android.com/reference/kotlin/androidx/compose/ui/semantics/package-summary#(androidx.compose.ui.semantics.SemanticsPropertyReceiver).testTagsAsResourceId()) allows developers to set an arbitrary string without the prefix rule. [Interoperability with UiAutomator](https://developer.android.com/jetpack/compose/testing) also explains how to set it. By default UIA2 driver adds the above prefixes automatically to all resource id locators if they are not prefixed, but in case of such \"special\" apps this feature might be disabled by assigning the setting to `true`.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Settings API","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Settings API\n\nincludeExtrasInPageSource | boolean | Whether to include `extras` element attribute in the XML page source result. Then, XPath locator can find the element by the extras. Its value consists of combined [getExtras](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#getExtras()) as `keys=value` pair separated by a semicolon (`;`), thus you may need to find the element with partial matching like `contains` e.g. `driver.find_element :xpath, '//*[contains(@extras, \"AccessibilityNodeInfo.roleDescription=\")]'`. The value could be huge if elements in the XML page source have large `extras`. It could affect the performance of XML page source generation.\nincludeA11yActionsInPageSource | boolean | Whether to include `actions` element attribute in the XML page source result. Its value consists of names of available accessibility actions from [getActionList](https://developer.android.com/reference/android/view/accessibility/AccessibilityNodeInfo#getActionList()), separated by a comma. The value could be huge if elements in the XML page source have a lot of actions and could affect the performance of XML page source generation.\nsnapshotMaxDepth | int | The number of maximum depth for the source tree snapshot. The default value is `70`. This number should be in range [1, 500]. A part of the elements source tree might be lost if the value is too low. Also, StackOverflowError might be caused if the value is too high (Issues [12545](https://github.com/appium/appium/issues/12545), [12892](https://github.com/appium/appium/issues/12892)). The available driver version is `2.27.0` or higher.\ncurrentDisplayId | int | The id of the display that should be used when finding elements, taking screenshots, etc. It can be found in the output of `adb shell dumpsys display` (search for `mDisplayId`). The default value is [Display.DEFAULT_DISPLAY](https://developer.android.com/reference/android/view/Display#DEFAULT_DISPLAY). See the [Multi-Window Testing Guide](docs/android-multiwindow.md) for detailed information about windows, displays, and how this setting affects element location. Set this setting to `-1`\nin order to reset it.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Settings API","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Settings API\n\nin order to reset it.\nalwaysTraversableViewClasses | string | Allows to continue the tree traversal for user defined classes even though the node itself is invisible. The default logic for the UI tree traversal (controlled by the `allowInvisibleElements` setting) is to stop recursing when an invisible node is found. However, with certain Jetpack Compose classes (e.g. androidx.compose.ui.viewinterop.ViewFactoryHolder), it is possible that invisible parent nodes have visible child nodes. See [Google issue \\#354958193](https://issuetracker.google.com/issues/354958193) and [UIA2 server issue \\#709](https://github.com/appium/appium-uiautomator2-server/issues/709) for more details. This setting only affects the XPath lookup and the page source buildup. You can provide a comma separated list of glob patterns, that will be used as an exemption list: `androidx.compose.ui.viewinterop.*,android.widget.ImageButton`.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Settings API","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions\n\nBeside of standard W3C APIs the driver provides the below custom command extensions to execute platform specific scenarios. Use the following source code examples in order to invoke them from your client code:\n\n```java\n// Java 11+\nvar result = driver.executeScript(\"mobile: <methodName>\", Map.ofEntries(\n Map.entry(\"arg1\", \"value1\"),\n Map.entry(\"arg2\", \"value2\")\n // you may add more pairs if needed or skip providing the map completely\n // if all arguments are defined as optional\n));\n```\n\n```js\n// WebdriverIO\nconst result = await driver.executeScript('mobile: <methodName>', [{\n arg1: \"value1\",\n arg2: \"value2\",\n}]);\n```\n\n```python\n# Python\nresult = driver.execute_script('mobile: <methodName>', {\n 'arg1': 'value1',\n 'arg2': 'value2',\n})\n```\n\n```ruby\n# Ruby\nresult = @driver.execute_script 'mobile: <methodName>', {\n arg1: 'value1',\n arg2: 'value2',\n}\n```\n\n```csharp\n// Dotnet\nobject result = driver.ExecuteScript(\"mobile: <methodName>\", new Dictionary<string, object>() {\n {\"arg1\", \"value1\"},\n {\"arg2\", \"value2\"}\n});\n```\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: shell\n\nExecutes the given shell command on the device under test via ADB connection. This extension exposes a potential security risk and thus is only enabled when explicitly activated by the `uiautomator2:adb_shell` server command line feature specifier.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: shell > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncommand | string | yes | Shell command name to execute, for example `echo` or `rm` | echo\nargs | Array&lt;string&gt; | no | Array of command arguments | `['-f', '/sdcard/myfile.txt']`\ntimeout | number | no | Command timeout in milliseconds. If the command blocks for longer than this timeout then an exception is going to be thrown. The default timeout is `20000` ms | 100000\nincludeStderr | boolean | no | Whether to include stderr stream into the returned result. `false` by default | true","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: shell > #### Returned Result\n\nDepending on the `includeStderr` value this API could either return a string, which is equal to the `stdout` stream content of the given command or a dictionary whose elements are `stdout` and `stderr` and values are contents of the corresponding outgoing streams. If the command exits with a non-zero return code then an exception is going to be thrown. The exception message will be equal to the command stderr.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: execEmuConsoleCommand\n\nExecutes a command through emulator telnet console interface and returns its output.\nThe `emulator_console` server feature must be enabled in order to use this method.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: execEmuConsoleCommand > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncommand | string | yes | The actual command to execute. See [Android Emulator Console Guide](https://developer.android.com/studio/run/emulator-console) for more details on available commands | help-verbose\nexecTimeout | number | no | Timeout used to wait for a server reply to the given command in milliseconds. `60000` ms by default | 100000\nconnTimeout | boolean | no | Console connection timeout in milliseconds. `5000` ms by default | 10000\ninitTimeout | boolean | no | Telnet console initialization timeout in milliseconds (the time between the connection happens and the command prompt). `5000` ms by default | 10000\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: execEmuConsoleCommand > #### Returned Result\n\nThe actual command output. An error is thrown if command execution fails.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: shell > #### Returned Result","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### Mobile Gesture Commands\n\nUiAutomator2 provides several extensions that allow to automate popular mobile gesture shortcuts:\n\n- mobile: dragGesture\n- mobile: flingGesture\n- mobile: doubleClickGesture\n- mobile: clickGesture\n- mobile: longClickGesture\n- mobile: pinchCloseGesture\n- mobile: pinchOpenGesture\n- mobile: swipeGesture\n- mobile: scrollGesture\n\nThese gestures are documented in the [Automating Mobile Gestures](docs/android-mobile-gestures.md) tutorial. Check [W3C Actions API](https://appiumpro.com/editions/29-automating-complex-gestures-with-the-w3c-actions-api) and\n[Low-Level Insights on Android Input Events](docs/actions.md) if you need to automate more complicated gestures.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: scroll\n\nScrolls the given scrollable element until an element identified by `strategy` and `selector` becomes visible. This function returns immediately if the destination element is already visible in the view port. Otherwise it would scroll to the very beginning of the scrollable control and tries to reach the destination element by scrolling its parent to the end step by step. The scroll direction (vertical or horizontal) is detected automatically.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: scroll > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId | string | no | The identifier of the scrollable element. It is required this element is a valid scrollable container and it was located by `-android uiautomator` strategy. If this property is not provided then the first currently available scrollable view is selected for the interaction. | 123456-3456-3435-3453453\nstrategy | string | yes | The following strategies are supported: `accessibility id` (UiSelector().description), `class name` (UiSelector().className), `-android uiautomator` (UiSelector) | 'accessibility id'\nselector | string | yes | The corresponding lookup value for the selected strategy. | 'com.mycompany:id/table'\nmaxSwipes | number | no | The maximum number of swipes to perform on the target scrollable view in order to reach the destination element. In case this value is unset then it would be retrieved from the scrollable element itself (vua `getMaxSearchSwipes()` property). | 10","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### Mobile Gesture Commands","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deepLink\n\nStart URI that may take users directly to the specific content in the app. Read [Reliably Opening Deep Links Across Platforms and Devices](https://appiumpro.com/editions/84-reliably-opening-deep-links-across-platforms-and-devices) for more details.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deepLink > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nurl | string | yes | The URL to start | theapp://login/\npackage | string | no | The name of the package to start the URI with. This argument was required previously but became optional since version 3.9.3 | 'com.mycompany'\nwaitForLaunch | boolean | no | If `false` then ADB won't wait for the started activity to return the control. `true` by default | false\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startLogsBroadcast\n\nStarts Android logcat broadcast websocket on the same host and port where Appium server is running at `/ws/session/:sessionId:/appium/device/logcat` endpoint. The method will return immediately if the web socket is already listening. Each connected websocket listener will receive logcat log lines as soon as they are visible to Appium. Read [Using Mobile Execution Commands to Continuously Stream Device Logs with Appium](https://appiumpro.com/editions/55-using-mobile-execution-commands-to-continuously-stream-device-logs-with-appium) for more details.\n\nConsider using [logs broadcast via BiDi](./docs/bidi.md#logentryadded) over this extension.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopLogsBroadcast\n\nStops the previously started logcat broadcasting websocket server. This method will return immediately if no server is running. Read [Using Mobile Execution Commands to Continuously Stream Device Logs with Appium](https://appiumpro.com/editions/55-using-mobile-execution-commands-to-continuously-stream-device-logs-with-appium) for more details.\n\nConsider using [logs broadcast via BiDi](./docs/bidi.md#logentryadded) over this extension.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deviceidle\n\nThis is a wrapper to 'adb shell dumpsys deviceidle' interface.\nRead [Diving Into Android 'M' Doze](https://www.protechtraining.com/blog/post/diving-into-android-m-doze-875) for more details.\nThis API only exists since Android 6.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deepLink","sectionCount":5,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deviceidle > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\naction | whitelistAdd or whitelistRemove | yes | The name of the action to perform | whitelistAdd\npackages | string or string[] | yes | One or more package names to perfom the above action on | 'com.mycompany'\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: acceptAlert\n\nTries to accept an Android alert. This method might not always be reliable as there is no single standard for how Android alerts should look like within the Accessibility representation.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: acceptAlert > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbuttonLabel | string | no | The name/text of the alert button to click in order to accept it. If not provided then the driver will try to autodetect it | Accept\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: dismissAlert\n\nTries to dismiss an Android alert. This method might not always be reliable as there is no single standard for how Android alerts should look like within the Accessibility representation.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: dismissAlert > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbuttonLabel | string | no | The name/text of the alert button to click in order to dismiss it. If not provided then the driver will try to autodetect it | Dismiss\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: batteryInfo\n\nRetrieves the battery information from the device under test.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: batteryInfo > #### Returned Result\n\nThe extension returns a dictionary whose entries are:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nlevel | number | Battery level in range [0.0, 1.0], where 1.0 means 100% charge. -1 is returned if the actual value cannot be retrieved from the system. | 0.5\nstate | number| Battery state. The following values are possible: BATTERY_STATUS_UNKNOWN = 1; BATTERY_STATUS_CHARGING = 2; BATTERY_STATUS_DISCHARGING = 3; BATTERY_STATUS_NOT_CHARGING = 4; BATTERY_STATUS_FULL = 5. -1 is returned if the actual value cannot be retrieved from the system. | 4","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deviceidle > #### Arguments","sectionCount":7,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deviceInfo\n\nRetrieves the information about the device under test, like the device model, serial number, network connectivity info, etc.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deviceInfo > #### Returned Result\n\nThe extension returns a dictionary whose entries are the device properties. Check https://github.com/appium/appium-uiautomator2-server/blob/master/app/src/main/java/io/appium/uiautomator2/handler/GetDeviceInfo.java to get the full list of returned keys and their corresponding values.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: resetAccessibilityCache\n\nResets the accessibility cache on the device. This can be useful when the accessibility\nservice cache becomes stale and needs to be refreshed to reflect the current UI state.\nThe driver does cache reset automatically before any element lookup as well as before\nretrieving a page source, hovewer it makes sense to call this method manually to avoid stale reference errors or interaction issues if the application under test posseses\nhighly dynamic elements. Note that this methods also waits until app under test becomes\nidle, so it might also slow down your automation if called too often under non-idling\ncircumstances.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listWindows\n\nGets a list of windows on all displays. For Android API 30+ (R), uses `getWindowsOnAllDisplays()` to retrieve windows from all displays. For older APIs, uses `getWindows()` which only returns windows from the default display.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deviceInfo","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listWindows > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nfilters | object | no | Optional filters to apply to the window list. All filters are applied with AND logic (all must match). Supported filter keys: | `{packageName: 'com.example.app', displayId: 0}`\n | | | | `packageName` (string): Package name pattern with glob support (e.g., `com.example.*`) |\n | | | | `windowId` (number): Window identifier |\n | | | | `displayId` (number): Display identifier |\n | | | | `physicalDisplayId` (string): Physical display identifier (as string to avoid JavaScript number precision issues) |\n | | | | `type` (number): Window type (see [AccessibilityWindowInfo.TYPE_*](https://developer.android.com/reference/android/view/accessibility/AccessibilityWindowInfo#TYPE_APPLICATION) constants) |\n | | | | `title` (string): Window title pattern with glob support |\n | | | | `layer` (number): Window Z-order layer (higher values are on top) |\n | | | | `isAccessibilityFocused` (boolean): Whether the window has accessibility focus |\n | | | | `isActive` (boolean): Whether the window is active |\n | | | | `isFocused` (boolean): Whether the window has input focus |\n | | | | `isInPictureInPictureMode` (boolean): Whether the window is in picture-in-picture mode |\nskipScreenshots | boolean | no | Whether to skip taking screenshots for each window. Defaults to `false`. Setting this to `true` can improve performance. Screenshots are only available on Android API 34+ even when this is `false`. | true","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listWindows > #### Arguments","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listWindows > #### Returned Result\n\nThe extension returns an array of window information objects. Each object contains:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nwindowId | number \\| null | Window identifier (may be null if the window ID cannot be determined) | 42\ndisplayId | number | Display identifier where the window is located | 0\nphysicalDisplayId | string \\| null | Physical display identifier (may be null). Returned as a string to avoid JavaScript number precision issues with large values. | '1234567890'\nvirtualDisplayId | string \\| null | Virtual display identifier (may be null). Only set for virtual displays, null otherwise. Parsed from 'dumpsys SurfaceFlinger --displays' output by matching display name. | '12345'\nrect | object | Window bounds rectangle with `left`, `top`, `right`, `bottom` properties | `{left: 0, top: 0, right: 1080, bottom: 1920}`\npackageName | string \\| null | Package name of the application that owns this window (may be null) | `com.example.app`\nscreenshot | string \\| null | Base64-encoded PNG screenshot of the window (may be null). Only available on Android API 34+ and when `skipScreenshots` is `false`. | `iVBORw0KGgoAAAANSUhEUgAA...`\ntype | number | Window type. See [AccessibilityWindowInfo.TYPE_*](https://developer.android.com/reference/android/view/accessibility/AccessibilityWindowInfo#TYPE_APPLICATION) constants for possible values (e.g., `TYPE_APPLICATION`, `TYPE_INPUT_METHOD`, `TYPE_SYSTEM`, `TYPE_ACCESSIBILITY_OVERLAY`, `TYPE_SPLIT_SCREEN_DIVIDER`). | 1\ntitle | string \\| null | Window title (may be null) | 'My App Window'\nlayer | number | Window Z-order layer. Higher values indicate windows that are drawn on top of windows with lower layer values. | 100\nisAccessibilityFocused | boolean | Whether the window has accessibility focus | true\nisActive | boolean | Whether the window is active | true\nisFocused | boolean | Whether the window has input focus | true\nisInPictureInPictureMode | boolean | Whether the window is in picture-in-picture mode | false\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listDisplays\n\nGets a list of all displays available on the device.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listWindows > #### Returned Result","sectionCount":2,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listDisplays > #### Returned Result\n\nThe extension returns an array of display information objects. Each object contains:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nid | number | Display identifier (logical display ID). This is the value used by the `currentDisplayId` setting. | 0\nname | string \\| null | Display name (may be null) | 'Built-in Screen'\nphysicalId | string \\| null | Physical display identifier (may be null). Returned as a string to avoid JavaScript number precision issues with large values. This is the value used by the `mobile: screenshots` method. | '1234567890'\nvirtualId | string \\| null | Virtual display identifier (may be null). Only set for virtual displays, null otherwise. Parsed from 'dumpsys SurfaceFlinger --displays' output by matching display name. | '12345'\nmetrics | object | Display metrics containing size and density information. See below for details. | See metrics table\nisDefault | boolean | Whether this is the default display | true","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listDisplays > #### Returned Result","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listDisplays > #### Display Metrics\n\nThe `metrics` object contains the following properties:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nwidthPixels | number | Display width in pixels | 1080\nheightPixels | number | Display height in pixels | 1920\ndensity | number | Display density (logical density factor). This is a scaling factor for the display. | 2.625\ndensityDpi | number | Display density in DPI (dots per inch) | 420\nscaledDensity | number | Scaled density factor for fonts. This is typically the same as `density` but may be adjusted by the user's font size preference. | 2.625\nxdpi | number | Exact physical pixels per inch of the screen in the X dimension | 420.0\nydpi | number | Exact physical pixels per inch of the screen in the Y dimension | 420.0\n\n**Example:**\n```python\n# List all displays\ndisplays = driver.execute_script('mobile: listDisplays')\n\nfor display in displays:\n print(f\"Display ID: {display['id']}\")\n print(f\" Name: {display['name']}\")\n print(f\" Physical ID: {display['physicalId']}\")\n if display.get('virtualId'):\n print(f\" Virtual ID: {display['virtualId']}\")\n print(f\" Is default: {display['isDefault']}\")\n print(f\" Size: {display['metrics']['widthPixels']}x{display['metrics']['heightPixels']}\")\n print(f\" Density: {display['metrics']['density']} ({display['metrics']['densityDpi']} DPI)\")\n```\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getDeviceTime\n\nRetrieves the current device's timestamp.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getDeviceTime > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nformat | string | no | The set of format specifiers. Read https://momentjs.com/docs/ to get the full list of supported datetime format specifiers. The default format is `YYYY-MM-DDTHH:mm:ssZ`, which complies to ISO-8601 | YYYY-MM-DDTHH:mm:ssZ\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getDeviceTime > #### Returned Result\n\nThe device timestamp string formatted according to the given specifiers\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: changePermissions\n\nChanges package permissions in runtime.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listDisplays > #### Display Metrics","sectionCount":5,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: changePermissions > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\npermissions | string or Array&lt;string&gt; | yes | The full name of the permission to be changed or a list of permissions. Consider checking [the full list](https://developer.android.com/reference/android/Manifest.permission) of standard Android permission names. If `all` magic string is passed (available since driver version 2.8.0) and `target` equals `pm` (the default value) then the chosen action is going to be applied to all permissions requested/granted by the 'appPackage'. If `target` is set to `appops` (available since v2.11.0) then check [AppOpsManager.java](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java) sources to get the full list of supported appops permission names for the given Android platform. The `all` magic string is unsupported for the `appops` target. | `['android.permission.ACCESS_FINE_LOCATION', 'android.permission.BROADCAST_SMS']` `all` `['READ_SMS', 'ACCESS_NOTIFICATIONS']`\nappPackage | string | no | The application package to set change permissions on. Defaults to the package name under test | com.mycompany.myapp\naction | string | no | Either `grant` (the default action) or `revoke` if `target` is set to `pm`, otherwise one of: `allow` (default), `deny`, `ignore`, `default`. | allow\ntarget | string | no | Either `pm` (default) or `appops` (available since v2.11.0). The `appops` one requires *adb_shell* server security option to be enabled | appops\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPermissions\n\nGets runtime permissions list for the given application package.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPermissions > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntype | string | no | One of possible permission types to get. Can be one of: `denied`, `granted` or `requested` (the default value). | granted\nappPackage | string | no | The application package to get permissions from. Defaults to the package name under test | com.mycompany.myapp\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPermissions > #### Returned Result\n\nArray of strings, where each string is a permission name. the array could be empty.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: changePermissions > #### Arguments","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: performEditorAction\n\nPerforms IME action on the _currently focused_ edit element.\n\nVery often Android developers use [onEditorAction](https://developer.android.com/reference/android/widget/TextView.OnEditorActionListener.html#onEditorAction(android.widget.TextView,%20int,%20android.view.KeyEvent)) callback with `actionId` argument to implement actions handling, for example, when `Search` or `Done` button is pressed on the on-screen keyboard. This mobile extension is supposed to emulate the invokation of such callback on the focused element.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: performEditorAction > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\naction | string | yes | The name or an integer code of the editor action to be executed. The following action names are supported: `normal, unspecified, none, go, search, send, next, done, previous`. Read [EditorInfo](https://developer.android.com/reference/android/view/inputmethod/EditorInfo) for more details on this topic. | search\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startScreenStreaming\n\nStarts device screen broadcast by creating MJPEG server. Multiple calls to this method have no effect unless the previous streaming session is stopped. This method only works if the `adb_screen_streaming` feature is enabled on the server side. It is also required that [GStreamer](https://gstreamer.freedesktop.org/) with `gst-plugins-base`, `gst-plugins-good` and `gst-plugins-bad` packages are installed and available in PATH on the server machine.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: performEditorAction","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startScreenStreaming > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nwidth | number | no | The scaled width of the device's screen. If unset then the script will assign it to the actual screen width measured in pixels. | 768\nheight | number | no | The scaled height of the device's screen. If unset then the script will assign it to the actual screen height measured in pixels. | 1024\nbitRate | number | no | The video bit rate for the video, in bits per second. The default value is 4000000 (4 Mb/s). You can increase the bit rate to improve video quality, but doing so results in larger movie files. | 1024000\nhost | string | no | The IP address/host name to start the MJPEG server on. You can set it to `0.0.0.0` to trigger the broadcast on all available network interfaces. `127.0.0.1` by default | 0.0.0.0\npathname | string | no | The HTTP request path the MJPEG server should be available on. If unset then any pathname on the given `host`/`port` combination will work. Note that the value should always start with a single slash: `/` | /myserver\ntcpPort | number | no | The port number to start the internal TCP MJPEG broadcast on. This type of broadcast always starts on the loopback interface (`127.0.0.1`). `8094` by default | 5024\nport | number | no | The port number to start the MJPEG server on. `8093` by default | 5023\nquality | number | no | The quality value for the streamed JPEG images. This number should be in range [1, 100], where 100 is the best quality. `70` by default | 80\nconsiderRotation | boolean | no | If set to `true` then GStreamer pipeline will increase the dimensions of the resulting images to properly fit images in both landscape and portrait orientations. Set it to `true` if the device rotation is not going to be the same during the broadcasting session. `false` by default | false\nlogPipelineDetails | boolean | no | Whether to log GStreamer pipeline events into the standard log output. Might be useful for debugging purposes. `false` by default | true\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopScreenStreaming\n\nStop the previously started screen streaming. If no screen streaming server has been started then nothing is done.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startScreenStreaming > #### Arguments","sectionCount":2,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getNotifications\n\nRetrieves Android notifications via Appium Settings helper. Appium Settings app itself must be *manually* granted to access notifications under device Settings in order to make this feature working. Different vendors [might](https://github.com/appium/io.appium.settings/issues/147#issue-2130780990) require more than just the normal Notification permissions at the usual Apps menu. Try to look in places like Privacy menus if you are getting zero items retrieved while expecting some results.\n\nAppium Settings helper keeps all the active notifications plus notifications that appeared while it was running in the internal buffer, but no more than 100 items altogether. Newly appeared notifications are always added to the head of the notifications array. The `isRemoved` flag is set to `true` for notifications that have been removed.\nSee https://developer.android.com/reference/android/service/notification/StatusBarNotification and https://developer.android.com/reference/android/app/Notification.html for more information on available notification properties and their values.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getNotifications > #### Returned Result\n\nThe example output is:\n```json\n{\n \"statusBarNotifications\":[\n {\n \"isGroup\":false,\n \"packageName\":\"io.appium.settings\",\n \"isClearable\":false,\n \"isOngoing\":true,\n \"id\":1,\n \"tag\":null,\n \"notification\":{\n \"title\":null,\n \"bigTitle\":\"Appium Settings\",\n \"text\":null,\n \"bigText\":\"Keep this service running, so Appium for Android can properly interact with several system APIs\",\n \"tickerText\":null,\n \"subText\":null,\n \"infoText\":null,\n \"template\":\"android.app.Notification$BigTextStyle\"\n },\n \"userHandle\":0,\n \"groupKey\":\"0|io.appium.settings|1|null|10133\",\n \"overrideGroupKey\":null,\n \"postTime\":1576853518850,\n \"key\":\"0|io.appium.settings|1|null|10133\",\n \"isRemoved\":false\n }\n ]\n}\n```\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: openNotifications\n\nOpens notifications drawer on the device under test. Does nothing if the drawer is already opened. Available since driver version 2.23","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getNotifications","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listSms\n\nRetrieves the list of the most recent SMS properties list via Appium Settings helper. Messages are sorted by date in descending order.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listSms > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nmax | number | no | The maximum count of recent messages to retrieve. `100` by default | 10\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listSms > #### Returned Result\n\nThe example output is:\n```json\n {\n \"items\":[\n {\n \"id\":\"2\",\n \"address\":\"+123456789\",\n \"person\":null,\n \"date\":\"1581936422203\",\n \"read\":\"0\",\n \"status\":\"-1\",\n \"type\":\"1\",\n \"subject\":null,\n \"body\":\"\\\"text message2\\\"\",\n \"serviceCenter\":null\n },\n {\n \"id\":\"1\",\n \"address\":\"+123456789\",\n \"person\":null,\n \"date\":\"1581936382740\",\n \"read\":\"0\",\n \"status\":\"-1\",\n \"type\":\"1\",\n \"subject\":null,\n \"body\":\"\\\"text message\\\"\",\n \"serviceCenter\":null\n }\n ],\n \"total\":2\n }\n```\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: type\n\nTypes the given Unicode string. It is expected that the focus is already put to the destination input field before this method is called. The main difference between this method and the sendKeys one is that it emulates `true` typing like it was done from an on-screen keyboard. It also properly supports Unicode input characters.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: type > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntext | string | yes | The text to type | testing\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: sensorSet\n\nEmulate changing of sensor values on the connected emulator.\nThis extension does not work on real devices.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listSms","sectionCount":6,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: sensorSet > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nsensorType | string | yes | The set of all supported sensor types could be found in [adb-emu-commands.js](https://github.com/appium/appium-adb/blob/master/lib/tools/adb-emu-commands.js) (look for *SENSORS* object values). Check the output of `sensor status` command in the [emulator console](https://developer.android.com/studio/run/emulator-console) to see more details on the available sensor types | light\nvalue | string | yes | Check the output of `sensor get <sensorType>` command in the [emulator console](https://developer.android.com/studio/run/emulator-console) to see the acceptable value format for the given sensor type | 50\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pullFile\n\nPulls a remote file from the device.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pullFile > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | The full path to the remote file or a specially formatted path, which points to an item inside an app bundle, for example `@my.app.id/my/path`. It is mandatory for the app bundle to have [debugging enabled](https://developer.android.com/studio/debug) in order to use the latter remotePath format. If the file with the given name does not exist then an exception will be thrown. | /sdcard/foo.bar\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pullFile > #### Returned Result\n\nBase64-encoded string, which represents the content of the remote file.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pushFile\n\nPushes a local file to the device.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pushFile > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | The path on the device to where the payload should be written. The value format is similar to the one used in [pullFile](#mobile-pullfile) extension. If the file with the same name already exists then it will be silently overridden. | /sdcard/foo.bar\npayload | string | yes | Base64-encoded content of the file to be pushed. | QXBwaXVt","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: sensorSet > #### Arguments","sectionCount":6,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pullFolder\n\nPulls a remote folder from the device.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pullFolder > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | Same as for [pullFile](#mobile-pullfile) extension, but should be pointing to a remote folder | /sdcard/yolo/\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pullFolder > #### Returned Result\n\nBase64-encoded string, which represents the zipped content of the remote folder.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deleteFile\n\nDeletes a file on the remote device.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: deleteFile > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | The full path to the remote file or a file inside an application bundle | `/sdcard/myfile.txt` or `@my.app.id/path/in/bundle`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isAppInstalled\n\nVerify whether an application is installed on the device under test.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isAppInstalled > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nappId | string | yes | The identifier of the application package to be checked | `my.app.id`\nuser | number or string | no | The user ID for which the package is installed. The `current` user is used by default | 1006\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isAppInstalled > #### Returned Result\n\nTrue or false\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listApps\n\nLists all installed packages on the Android device, optionally filtered by user.\nAn exception will be thrown on devices running Android API below level 26.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listApps > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nuser | number or string | no | The user ID for which the package is installed. The `current` user is used by default | 1006","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pullFolder","sectionCount":10,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listApps > #### Returned Result\n\nA map where keys are packageName and values are maps of platform-specific app properties since UIAutomator2 driver v7.0.0.\nUIAutomator2 driver v6.9.0 and v6.9.1 were a list of installed package names.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: queryAppState\n\nQueries the current state of the app.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: queryAppState > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nappId | string | yes | The identifier of the application package to be checked | `my.app.id`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: queryAppState > #### Returned Result\n\nThe following numbers could returned:\n- The app is not installed: `0`\n- The app is installed and is not running: `1`\n- The app is running in background: `3`\n- The app is running in foreground: `4`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: activateApp\n\nActivates the given application or launches it if necessary.\nThe action literally simulates\nclicking the corresponding application icon on the dashboard.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: activateApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nappId | string | yes | The identifier of the application package to be activated | `my.app.id`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: removeApp\n\nRemove the corresponding application if is installed.\nThe call is ignored if the app is not installed.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: removeApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nappId | string | yes | The identifier of the application package to be removed | `my.app.id`\ntimeout | number | no | The count of milliseconds to wait until the app is terminated. 20000ms by default. | 1500, 0\nkeepData | boolean | no | Set to true in order to keep the application data and cache folders after uninstall. | true\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: removeApp > #### Returned Result\n\nTrue is the app has been found on the device and successfully removed. Otherwise false.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: listApps > #### Returned Result","sectionCount":9,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: terminateApp\n\nTerminates the app and waits until the app is terminated up to the given timeout\nby checking the app state to ensure if the app process is actually stopped.\n\nThe app state check can be skipped if the given timeout is lower or equal to zero since UIAutomator driver 2.9.0.\nThe skip helps when you want to terminate the app process but do not want to check the process existence\nbecause the app under test may, for example, restart it automatically.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: terminateApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nappId | string | yes | The identifier of the application package to be terminated | `my.app.id`\ntimeout | number | no | The count of milliseconds to wait until the app is terminated. 500ms by default. | 1500, 0\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: terminateApp > #### Returned Result\n\nTrue if the app has been successfully terminated.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: installApp\n\nInstalls the given application package to the device under test.\nIt might raise the `INSTALL_FAILED_VERSION_DOWNGRADE` error if the installation was a version downgrade.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: terminateApp","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: installApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nappPath | string | yes | The local .apk(s) path on the server filesystem or a remote url. | `/app/path.apk`\ntimeout | number | no | The count of milliseconds to wait until the app is installed.. 6000ms by default. | 120000\nallowTestPackages | boolean | no | Set to true in order to allow test packages installation. false by default | true\nuseSdcard | boolean | no | Set to true to install the app on sdcard instead of the device memory. false by default | true\ngrantPermissions | boolean | no | Set to true in order to grant all the permissions requested in the application's manifest automatically after the installation is completed under Android 6+. The targetSdkVersion in the application manifest must be greater or equal to 23 and the Android version on the device under test must be greater or equal to Android 6 (API level 23) to grant permissions. Applications whose targetSdkVersion is lower than or equal to 22 must be reisntalled to grant permissions for Android 6+ devices. false by default | true\nreplace | boolean | no | Set it to false if you don't want the application to be upgraded/reinstalled if it is already present on the device, but throw an error instead. true by default | false\ncheckVersion | boolean | no | Set to true, in order to skip the application installation if the device under test has a greater or equal to the application version. It may help to avoid `INSTALL_FAILED_VERSION_DOWNGRADE` error and unnecessary installation. | true\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: clearApp\n\nDeletes all data associated with a package. Calls `adb shell pm clear` under the hood.\nThe app should be accessible, should not be running,\nand should exist on the device under test for this extension to work properly.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: clearApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nappId | string | yes | The identifier of the application package to be cleared | `my.app.id`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: clearApp > #### Returned Result\n\nStdout of the corresponding adb command.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: installApp > #### Arguments","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity\n\nStarts the given activity intent. Invokes `am start`/`am start-activity` command under the hood.\nThis method extends the functionality of the [Start Activity](#applications-management) app management API.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nintent | string | yes | The full name of the activity intent to start | `com.some.package.name/.YourActivityClassName`\nuser | number or string | no | The user ID for which the service is started. The `current` user is used by default | 1006\nwait | boolean | no | Set it to `true` if you want to block the method call until the Activity Manager's process returns the control to the system. | false\nstop | boolean | no | Set it to `true` to force stop the target app before starting the activity. | false\nwindowingMode | integer | no | The windowing mode to launch the activity into. Check [WindowConfiguration.java](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/WindowConfiguration.java) for more details on possible windowing modes (constants starting with `WINDOWING_MODE_`). | 1\nactivityType | integer | no | The activity type to launch the activity as. Check [WindowConfiguration.java](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/WindowConfiguration.java) for more details on possible activity types (constants starting with `ACTIVITY_TYPE_`). | 1\naction | string | no | Action name. The actual value for the Activity Manager's `-a` argument. | android.intent.action.MAIN\nuri | string | no | Unified resource identifier. The actual value for the Activity Manager's `-d` argument. | https://appium.io\nmimeType | string | no | Mime type. The actual value for the Activity Manager's `-t` argument. | application/json\nidentifier | string | no | Optional identifier. The actual value for the Activity Manager's `-i` argument. | my_identifier\ncategories | string or Array&lt;string&gt; | no | One or more category names. The actual value(s) for the Activity Manager's `-c` argument. | android.intent.category.LAUNCHER\ncomponent | string | no | Component name. The actual value for the Activity Manager's `-n` argument. | com.myapp/com.myapp.SplashActivity\npackage | string | no | Package name. The actual value for the Activity Manager's `-p` argument. | com.myapp","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity > #### Arguments","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity > #### Arguments\n\npackage | string | no | Package name. The actual value for the Activity Manager's `-p` argument. | com.myapp\nextras | Array&lt;Array&lt;string&gt;&gt; | no | Optional intent arguments. Must be represented as an array of arrays, where each subarray item contains two (only in case it no value is required for the given type) or three string items: value type, key (variable name) and the value itself. Supported value types are: `s`: string. Value must be a valid string; `sn`: null. Value is ignored for this type; `z`: boolean. Value must be either `true` or `false`; `i`: integer. Value must be a valid 4-byte integer number; `l`: long. Value must be a valid 8-byte long number; `f`: float: Value must be a valid float number; `u`: uri. Value must be a valid uniform resource identifier string; `cn`: component name. Value must be a valid component name string; `ia`: Integer[]. Value must be a string of comma-separated integers; `ial`: List&lt;Integer&gt;. Value must be a string of comma-separated integers; `la`: Long[]. Value must be a string of comma-separated long numbers; `lal`: List&lt;Long&gt;. Value must be a string of comma-separated long numbers; `fa`: Float[]. Value must be a string of comma-separated float numbers; `fal`: List&lt;Float&gt;. Value must be a string of comma-separated float numbers; `sa`: String[]. Value must be comma-separated strings. To embed a comma into a string escape it using \"\\,\"; `sal`: List&lt;String&gt;. Value must be comma-separated strings. To embed a comma into a string, escape it using \"\\,\" | [['s', 'varName1', 'My String1'], ['s', 'varName2', 'My String2'], ['ia', 'arrName', '1,2,3,4']]\nflags | string | no | Intent startup-specific flags as a hexadecimal string. Check [Intent documentation](https://developer.android.com/reference/android/content/Intent.html) for the list of available flag values (constants starting with `FLAG_ACTIVITY_`). Flag values could be merged using the logical 'or' operation. | 0x10200000 is the combination of two flags: 0x10000000 `FLAG_ACTIVITY_NEW_TASK` `|` 0x00200000 `FLAG_ACTIVITY_RESET_TASK_IF_NEEDED`","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity > #### Arguments","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity > #### Returned Result\n\nThe actual stdout of the downstream `am` command.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity > #### Example\n\nUse the code snippet below to represent the following shell command: `shell am start-activity -W -n io.appium.android.apis/io.appium.android.apis.ApiDemos -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000'`, which is usually similar to what is called in a new session request.\nIf you replace `'io.appium.android.apis/io.appium.android.apis.ApiDemos'` with your expected launchable activity, it would be the alternative method to start the activity in session.\n\nPlease check [how appium adds flags](https://github.com/appium/appium-android-driver/blob/master/lib/commands/intent.js) for more details to understand how Appium builds flags.\n\n```ruby\n# Ruby\ndriver.execute_script 'mobile: startActivity', {\n wait: true,\n stop: true,\n action: 'android.intent.action.MAIN',\n component: 'io.appium.android.apis/io.appium.android.apis.ApiDemos',\n categories: ['android.intent.category.LAUNCHER'],\n flags: '0x10200000'\n}\n```\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startService\n\nStarts the given service intent. Invokes `am startservice` or `am start-service` command under the hood.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startActivity > #### Returned Result","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startService > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nintent | string | no | The full name of the service intent to start | `com.some.package.name/.YourServiceSubClassName`\nuser | number or string | no | The user ID for which the service is started. The `current` user id is used by default | 1006\nforeground | boolean | no | Set it to `true` if your service must be started as a foreground service. The argument only works for Android 8 and above. | false\naction | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | android.intent.action.MAIN\nuri | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | https://appium.io\nmimeType | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | application/json\nidentifier | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | my_identifier\ncategories | string or Array&lt;string&gt; | no | See the documentation for [startActivity extension](#mobile-startactivity) | com.myapp/com.myapp.SplashActivity\ncomponent | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | android.intent.category.LAUNCHER\npackage | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | com.myapp\nextras | Array&lt;Array&lt;string&gt;&gt; | no | See the documentation for [startActivity extension](#mobile-startactivity) | [['s', 'varName1', 'My String1'], ['s', 'varName2', 'My String2'], ['ia', 'arrName', '1,2,3,4']]\nflags | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | 0x10200000 is the combination of two flags: 0x10000000 `FLAG_ACTIVITY_NEW_TASK` `|` 0x00200000 `FLAG_ACTIVITY_RESET_TASK_IF_NEEDED`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startService > #### Returned Result\n\nThe actual stdout of the downstream `am` command.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopService\n\nStops the given service intent. Invokes `am stopservice` or `am stop-service` command under the hood.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startService > #### Arguments","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopService > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nintent | string | no | The full name of the service intent to stop | `com.some.package.name/.YourServiceSubClassName`\nuser | number or string | no | The user ID for which the service is started. The `current` user id is used by default | 1006\naction | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | android.intent.action.MAIN\nuri | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | https://appium.io\nmimeType | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | application/json\nidentifier | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | my_identifier\ncategories | string or Array&lt;string&gt; | no | See the documentation for [startActivity extension](#mobile-startactivity) | com.myapp/com.myapp.SplashActivity\ncomponent | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | android.intent.category.LAUNCHER\npackage | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | com.myapp\nextras | Array&lt;Array&lt;string&gt;&gt; | no | See the documentation for [startActivity extension](#mobile-startactivity) | [['s', 'varName1', 'My String1'], ['s', 'varName2', 'My String2'], ['ia', 'arrName', '1,2,3,4']]\nflags | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | 0x10200000 is the combination of two flags: 0x10000000 `FLAG_ACTIVITY_NEW_TASK` `|` 0x00200000 `FLAG_ACTIVITY_RESET_TASK_IF_NEEDED`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: broadcast\n\nSend a broadcast Intent. Invokes `am broadcast` command under the hood.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopService > #### Arguments","sectionCount":2,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: broadcast > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nintent | string | no | The full name of the intent to broadcast | `com.some.package.name/.YourIntentClassName`\nuser | number or string | no | Specify which user to send to; if not specified then send to all users. Possible values are `all`/`current`/`<numeric user id>` | current\nreceiverPermission | string | no | Require receiver to hold the given permission | android.permission.READ_PROFILE\nallowBackgroundActivityStarts | boolean | no | The receiver may start activities even if in the background if set to `true` | false\naction | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | android.intent.action.MAIN\nuri | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | https://appium.io\nmimeType | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | application/json\nidentifier | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | my_identifier\ncategories | string or Array&lt;string&gt; | no | See the documentation for [startActivity extension](#mobile-startactivity) | com.myapp/com.myapp.SplashActivity\ncomponent | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | android.intent.category.LAUNCHER\npackage | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | com.myapp\nextras | Array&lt;Array&lt;string&gt;&gt; | no | See the documentation for [startActivity extension](#mobile-startactivity) | [['s', 'varName1', 'My String1'], ['s', 'varName2', 'My String2'], ['ia', 'arrName', '1,2,3,4']]\nflags | string | no | See the documentation for [startActivity extension](#mobile-startactivity) | 0x10200000 is the combination of two flags: 0x10000000 `FLAG_ACTIVITY_NEW_TASK` `|` 0x00200000 `FLAG_ACTIVITY_RESET_TASK_IF_NEEDED`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: broadcast > #### Returned Result\n\nThe actual stdout of the downstream `am` command.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getContexts\n\nRetrieves a WebViews mapping based on CDP endpoints","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: broadcast > #### Arguments","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getContexts > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nwaitForWebviewMs | number | no | Tells UiAutomator2 driver for how long (in milliseconds) to wait for web view(s) to appear since UiAutomator2 driver v2.53.0. If a Chrome process running on the device under test fails to create a connection to the devtools socket, then the chromedriver will rise an error similar to `failed to connect to socket 'localabstract:chrome_devtools_remote'` in UiAutomator2 driver. It could cause no WebViews found result, although a couple of retrials may fix it. This argument helps to keep trying to get WebView(s) up to the given time milliseconds as one command call. This issue tends to occur Chrome v115 and over so far. [issues#19251](https://github.com/appium/appium/issues/19251) contains more details. If set to `0`ms (the default value), then UiAutomator2 driver only checks the WebView(s) availability once. | 10000","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getContexts > #### Arguments","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getContexts > #### Returned Result\n\nThe following json demonstrates the example of WebviewsMapping object.\nNote that `description` in `page` can be an empty string most likely when it comes to Mobile Chrome)\n\n```json\n {\n \"proc\": \"@webview_devtools_remote_22138\",\n \"webview\": \"WEBVIEW_22138\",\n \"info\": {\n \"Android-Package\": \"io.appium.settings\",\n \"Browser\": \"Chrome/74.0.3729.185\",\n \"Protocol-Version\": \"1.3\",\n \"User-Agent\": \"Mozilla/5.0 (Linux; Android 10; Android SDK built for x86 Build/QSR1.190920.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36\",\n \"V8-Version\": \"7.4.288.28\",\n \"WebKit-Version\": \"537.36 (@22955682f94ce09336197bfb8dffea991fa32f0d)\",\n \"webSocketDebuggerUrl\": \"ws://127.0.0.1:10900/devtools/browser\"\n },\n \"pages\": [\n {\n \"description\": \"{\\\"attached\\\":true,\\\"empty\\\":false,\\\"height\\\":1458,\\\"screenX\\\":0,\\\"screenY\\\":336,\\\"visible\\\":true,\\\"width\\\":1080}\",\n \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/serve_rev/@22955682f94ce09336197bfb8dffea991fa32f0d/inspector.html?ws=127.0.0.1:10900/devtools/page/27325CC50B600D31B233F45E09487B1F\",\n \"id\": \"27325CC50B600D31B233F45E09487B1F\",\n \"title\": \"Releases · appium/appium · GitHub\",\n \"type\": \"page\",\n \"url\": \"https://github.com/appium/appium/releases\",\n \"webSocketDebuggerUrl\": \"ws://127.0.0.1:10900/devtools/page/27325CC50B600D31B233F45E09487B1F\"\n }\n ],\n \"webviewName\": \"WEBVIEW_com.io.appium.setting\"\n }\n```\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getChromeCapabilities\n\nRetrieves the Chrome capabilities that are being used for the current\nChromedriver session. This method is useful for debugging Chrome/webview\nautomation issues and understanding what capabilities are being applied to the\nChromedriver instance.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getContexts > #### Returned Result","sectionCount":2,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getChromeCapabilities > #### Returned Result\n\nThe extension returns a dictionary containing the Chrome capabilities that are\ncurrently being used by the Chromedriver session. The structure of the returned\nobject follows the standard Chrome/Chromium capabilities format and may include\nproperties such as:\n\n- `browserName`: The name of the browser (typically \"chrome\")\n- `browserVersion`: The version of Chrome/Chromium being automated\n- `platformName`: The platform name\n- Other standard WebDriver capabilities\n\nThe exact structure and properties may vary depending on\nthe Chrome version and the capabilities that were set during session creation.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: installMultipleApks\n\nInstall applications via `install-multiple` option.\nPlease read more details in the corresponding section of the `adb --help` command output.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: installMultipleApks > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\napks | Array&lt;string&gt; | yes | The path to APKs. Each path should be the full path to the apk to be installed, or an URL to a remote location. | `['/path/to/local.apk', 'https://github.com/appium/ruby_lib_core/blob/master/test/functional/app/api.apk.zip?raw=true']`\noptions | object | no | Installation options. If you want enable `-g` option, you could specify that `{grantPermissions: true}`. `allowTestPackages` corresponds `-t`, `useSdcard` corresponds `-s`, `replace` corresponds `-r` (`-r` is enabled by default), `partialInstall` corresponds `-p`. | `{grantPermissions: true, partialInstall: true}`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: lock\n\nLock the device (and optionally unlock it after a certain amount of time). Only simple (e.g. without a password) locks are supported.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: lock > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nseconds | number|string | no | The number of seconds after which to unlock the device. Set to `0` or leave it empty to require manual unlock (e.g. do not block and automatically unlock afterwards). | 5","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getChromeCapabilities > #### Returned Result","sectionCount":5,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: unlock\n\nUnlocks the device if it is locked. Noop if the device's screen is not locked.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: unlock > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nkey | string | yes | The unlock key. See the documentation on [appium:unlockKey](#device-locking) capability for more details | 12345\ntype | string | yes | The unlock type. See the documentation on [appium:unlockType](#device-locking) capability for more details | password\nstrategy | string | no | Unlock strategy. See the documentation on [appium:unlockStrategy](#device-locking) capability for more details | uiautomator\ntimeoutMs | number | no | Unlock timeout. See the documentation on [appium:unlockSuccessTimeout](#device-locking) capability for more details | 5000\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isLocked\n\nDetermine whether the device is locked.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isLocked > #### Returned Result\n\nEither `true` or `false`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setGeolocation\n\nSets emulated geolocation coordinates on the device under test.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: unlock","sectionCount":5,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setGeolocation > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nlatitude | number | yes | [Latitude](https://en.wikipedia.org/wiki/Latitude) value | 32.456\nlongitude | number | yes | [longitude](https://en.wikipedia.org/wiki/Longitude) value | 32.456\naltitude | number | no | [Altitude](https://en.wikipedia.org/wiki/Altitude) value. Zero by default | 5.678\nsatellites | number | no | Number of satellites being tracked (1-12). Available for emulators. | 2\nspeed | number | no | [Set the speed](https://developer.android.com/reference/android/location/Location#setSpeed(float)) in meters per second. Valid value is `0.0` or greater. | 30.0\nbearing | number | no | [Set the bearing](https://developer.android.com/reference/android/location/Location#setBearing(float)) at the time of this location, in degrees. Available for real devices. Valid values should be in range `[0, 360)`. | 10\naccuracy | number | no | [Set the horizontal accuracy](https://developer.android.com/reference/android/location/Location#setAccuracy(float)) in meters of this location. Available for real devices. Valid value is `0.0` or greater. | 10.0\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getGeolocation\n\nRetrieves current geolocation coordinates from the device under test. If coordinates are mocked/emulated\nthen these coordinates would be returned.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getGeolocation > #### Returned Result\n\nA map with the following entries:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nlatitude | number | [Latitude](https://en.wikipedia.org/wiki/Latitude) value | 32.456\nlongitude | number | [longitude](https://en.wikipedia.org/wiki/Longitude) value | 32.456\naltitude | number | [Altitude](https://en.wikipedia.org/wiki/Altitude) value | 5.678\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: resetGeolocation\n\nResets mocked geolocation provider to the default/system one. Only works for real devices.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setGeolocation > #### Arguments","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: refreshGpsCache\n\nSends a request to refresh the GPS cache on the device under test.\nBy default the location tracking is configured for\n[low battery consumption](https://github.com/appium/io.appium.settings/blob/master/app/src/main/java/io/appium/settings/LocationTracker.java),\nso you might need to call this extension periodically to get the updated geo\nlocation if the actual (or mocked) device location is changed too frequently.\nThe feature only works if the device under test has Google Play Services installed.\nIn case the vanilla\n[LocationManager](https://developer.android.com/reference/android/location/LocationManager)\nis used the device API level must be at version 30 (Android R) or higher.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: refreshGpsCache > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntimeoutMs | number | no | The maximum number of milliseconds to block until GPS cache is refreshed. If the API call does not receive a confirmation about successful cache refresh within this timeout then an error is thrown. Providing zero or a negative value to it skips waiting completely and does not check for any errors. 20000 ms by default. | 60000\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startMediaProjectionRecording\n\nStarts a new recording of the device activity using [Media Projection](https://developer.android.com/reference/android/media/projection/MediaProjection) API. This API is available since Android 10 (API level 29) and allows to record device screen and audio in high quality. Video and audio encoding is done by Android itself.\nThe recording is done by [Appium Settings helper](https://github.com/appium/io.appium.settings#internal-audio--video-recording).","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: refreshGpsCache","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startMediaProjectionRecording > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nresolution | string | no | The resolution of the resulting video, which usually equals to Full HD 1920x1080 on most phones, however you could change it to one of the following supported resolutions: \"1920x1080\", \"1280x720\", \"720x480\", \"320x240\", \"176x144\" | 1280x720\nmaxDurationSec | number | no | The maximum number of seconds allowed for the recording to run. 900 seconds by default (15 minutes) | 300\npriority | string | no | Recording thread priority is set to maximum (`high`) by default. However if you face performance drops during testing with recording enabled, you could reduce the recording priority to `normal` or `low`. | low\nfilename | string | no | You can type recording video file name as you want, but recording currently supports only \"mp4\" format so your filename must end with \".mp4\". An invalid file name will fail to start the recording. If not provided then the current timestamp will be used as file name. | screen.mp4\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startMediaProjectionRecording > #### Returned Result\n\n`true` if a new recording has successfully started. `false` if another recording is currently running.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isMediaProjectionRecordingRunning\n\nCheck if a media projection recording is currently running\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isMediaProjectionRecordingRunning > #### Returned Result\n\n`true` if a recording is running.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopMediaProjectionRecording\n\nStops a recording and retrieves the recently recorded media. If no recording has been started before then an error is thrown. If the recording has been already finished before this API has been called then the most recent recorded media is returned.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: startMediaProjectionRecording > #### Arguments","sectionCount":5,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopMediaProjectionRecording > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | no | The path to the remote location, where the resulting video should be uploaded. The following protocols are supported: http/https, ftp. Null or empty string value (the default setting) means the content of resulting file should be encoded as Base64 and passed as the endpoont response value. An exception will be thrown if the generated media file is too big to fit into the available process memory. | https://myserver.com/upload\nuser | string | no | The name of the user for the remote authentication. | admin\npass | string | no | The password for the remote authentication. | pa$$w0rd\nmethod | string | no | The http multipart upload method name. The 'PUT' one is used by default. | POST\nheaders | Map&lt;string, string&gt; | no | Additional headers mapping for multipart http(s) uploads | {'Agent': '007'}\nfileFieldName | string | no | The name of the form field, where the file content BLOB should be stored for http(s) uploads. `file` by default | blob\nformFields | Map&lt;string, string&gt; or Array&lt;Pair&gt; | no | Additional form fields for multipart http(s) uploads. | {'name': 'yolo.mp4'}\nuploadTimeout | number | no | The maximum number of milliseconds to wait until the media file is uploaded to the remote location. 240000 ms by default. | 30000\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopMediaProjectionRecording > #### Returned Result\n\nBase64-encoded content of the recorded media file if `remotePath` argument is falsy or an empty string.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getConnectivity\n\nReturns connectivity states for different services\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getConnectivity > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nservices | string or string[] | no | One or more services to get the connectivity for. Supported service names are: wifi, data, airplaneMode. If no service names are provided then all supported names are assumed by default. | [wifi, data]","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: stopMediaProjectionRecording > #### Arguments","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getConnectivity > #### Returned Result\n\nA map is returned containing the following possible items (depending on which values have been passed to `services` argument):\n\nName | Type | Description\n--- | --- | ---\nwifi | boolean | True if wifi is enabled\ndata | boolean | True if mobile data connection is enabled\nairplaneMode | boolean | True if Airplane Mode is enabled\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setConnectivity\n\nSet the connectivity state for different services. At least one valid service name must be provided in arguments.\nMissing values tell the driver to not change the corresponding service's state.\n\n> [!Note]\n>\n> Switching Wi-Fi and mobile data states reliably work on emulators for all Android versions.\n> Real devices support proper state switching only since Android 11.\n\n> [!Note]\n>\n> UiAutomator2 REST server app is running on the device under test and might be terminated/disconnected by Android\n> thus failing the driver session as a result of using this API. The only way to restore the session would be to quit it\n> after the network state is changed and then reopen it with `noReset` capability being set to `true` when the connectivity\n> is restored.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setConnectivity > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nwifi | booolean | no | Either to enable or disable Wi-Fi. | false\ndata | booolean | no | Either to enable or disable mobile data. | false\nairplaneMode | booolean | no | Either to enable or disable Airplane Mode. | false\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getAppStrings\n\nRetrieves string resources for the given app language. An error is thrown if strings cannot be fetched or no strings exist\nfor the given language abbreviation. Available since driver version 2.15.0\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getAppStrings > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nlanguage | string | no | The language abbreviation to fetch app strings mapping for. If no language is provided then strings for the default language on the device under test would be returned | fr","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getConnectivity > #### Returned Result","sectionCount":5,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getAppStrings > #### Returned Result\n\nApp strings map, where keys are resource identifiers.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: hideKeyboard\n\nTries to hide the on-screen keyboard. Throws an exception if the keyboard cannot be hidden.\nDoes nothing if the keyboard is already hidden.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: hideKeyboard > #### Returned Result\n\n`true` if the keyboard was successfully hidden or `false` if it was already invisible.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isKeyboardShown\n\nChecks if the system on-screen keyboard is visible.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isKeyboardShown > #### Returned Result\n\n`true` if the keyboard is visible\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pressKey\n\nEmulates single key press on the key with the given code. Available since driver version 2.17.0\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: pressKey > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nkeycode | number | yes | A valid Android key code. See [KeyEvent documentation](https://developer.android.com/reference/android/view/KeyEvent) for the list of available key codes | 0x00000099 (which is KEYCODE_NUMPAD_9)\nmetastate | number | no | An integer in which each bit set to 1 represents a pressed meta key. See [KeyEvent documentation](https://developer.android.com/reference/android/view/KeyEvent) for more details. | 0x00000010 (which is META_ALT_LEFT_ON)\nflags | number | no | Flags for the particular key event. See [KeyEvent documentation](https://developer.android.com/reference/android/view/KeyEvent) for more details. | 0x00000001 (which is FLAG_WOKE_HERE)\nisLongPress | boolean | no | Whether to emulate long key press. `false` by default. | true\nsource | number | no | Input device source. One or more [InputDevice.SOURCE_*](https://developer.android.com/reference/android/view/InputDevice) values (e.g. SOURCE_KEYBOARD, SOURCE_DPAD, SOURCE_GAMEPAD). Default is `257` or `0x101`, which maps to SOURCE_KEYBOARD. Multiple values can be combined using the logical OR operator. | 0x00000101 (SOURCE_KEYBOARD), 0x00000101 | 0x00000201 (SOURCE_KEYBOARD or SOURCE_DPAD)","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getAppStrings > #### Returned Result","sectionCount":7,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: backgroundApp\n\nPuts the app to the background and waits the given number of seconds. Then restores the app\nif necessary. The call is blocking. Available since driver version 2.19.0\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: backgroundApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nseconds | number | no | The amount of seconds to wait between putting the app to background and restoring it. Any negative value means to not restore the app after putting it to background (the default behavior). | 5\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getCurrentActivity\n\nReturns the name of the currently focused app activity. Available since driver version 2.20\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getCurrentActivity > #### Returned Result\n\nThe activity class name. Could be `null`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getCurrentPackage\n\nReturns the name of the currently focused app package identifier. Available since driver version 2.20\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getCurrentPackage > #### Returned Result\n\nThe package class name. Could be `null`\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getDisplayDensity\n\nReturns the display density value measured in DPI. Available since driver version 2.21\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getDisplayDensity > #### Returned Result\n\nThe actual DPI value as integer number\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getSystemBars\n\nReturns properties of various system bars. Available since driver version 2.21","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: backgroundApp","sectionCount":9,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getSystemBars > #### Returned Result\n\nA dictionary whose entries are:\n- `statusBar`\n- `navigationBar`\n\nValues are dictionaries with the following properties:\n- `visible`: Whether the bar is visible (equals to `false` if the bar is not present in the system info output)\n- `x`: Bar x coordinate (might be zero if the bar is not present in the system info output)\n- `y`: Bar y coordinate (might be zero if the bar is not present in the system info output)\n- `width`: Bar width (might be zero if the bar is not present in the system info output)\n- `height`: Bar height (might be zero if the bar is not present in the system info output)\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: fingerprint\n\nEmulate [fingerprint](https://learn.microsoft.com/en-us/xamarin/android/platform/fingerprint-authentication/enrolling-fingerprint) on Android Emulator. Only works on API 23+. Available since driver version 2.22\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: fingerprint > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nfingerprintId | number | yes | The value is the id for the finger that was \"scanned\". It is a unique integer that you assign for each virtual fingerprint. When the app is running you can run this same command each time the emulator prompts you for a fingerprint, you can run the adb command and pass it the fingerprintId to simulate the fingerprint scan. | 1\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: sendSms\n\nEmulate sending an SMS to the given phone number. Only works on emulators. Available since driver version 2.22\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: sendSms > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nphoneNumber | string | yes | The phone number to send SMS to | 0123456789\nmessage | string | yes | The SMS message payload | Hello\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: gsmCall\n\nEmulate a GSM call to the given phone number. Only works on emulators. Available since driver version 2.22","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getSystemBars > #### Returned Result","sectionCount":6,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: gsmCall > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nphoneNumber | string | yes | The phone number to call to | 0123456789\naction | call or accept or cancel or hold | yes | One of possible actions to take | accept\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: gsmSignal\n\nEmulate GSM signal strength change event. Only works on emulators. Available since driver version 2.22\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: gsmSignal > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nstrength | 0 or 1 or 2 or 3 or 4 | yes | One of possible signal strength values, where 4 is the best signal. | 3\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: gsmVoice\n\nEmulate GSM voice state change event. Only works on emulators. Available since driver version 2.22\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: gsmVoice > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nstate | on or off or denied or searching or roaming or home or unregistered | yes | Voice state | off\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: powerAC\n\nEmulate AC power state change. Only works on emulators. Available since driver version 2.22\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: powerAC > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nstate | on or off | yes | AC Power state | off\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: powerCapacity\n\nEmulate power capacity change. Only works on emulators. Available since driver version 2.22\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: powerCapacity > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\npercent | 0 to 100 | yes | Percentage value in range [0, 100] | 50\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: networkSpeed\n\nEmulate different network connection speed modes. Only works on emulators. Available since driver version 2.22","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: gsmCall > #### Arguments","sectionCount":10,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: networkSpeed > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nspeed | gsm or scsd or gprs or edge or umts or hsdpa or lte or evdo or full | yes | Mobile network speed mode name | edge\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: replaceElementValue\n\nSends a text to the given element by replacing its previous content. Available since driver version 2.22\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: replaceElementValue > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId | string | yes | Hexadecimal identifier of the destination text input | 123456-3456-3435-3453453\ntext | string | yes | The text to enter. It could also contain Unicode characters. If the text ends with `\\\\n` (the backslash must be escaped, so the char is NOT translated into `0x0A`) then the Enter key press is going to be emulated after it is entered (the `\\\\n` substring itself will be cut off from the typed text). | yolo\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: toggleGps\n\nSwitches GPS setting state. This API only works reliably since Android 12 (API 31). Available since driver version 2.23\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: isGpsEnabled\n\nReturns `true` if GPS is enabled on the device under test. Available since driver version 2.23\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPerformanceDataTypes\n\nFetches the list of supported performance data types that could be used as `dataType` argument value to [mobile: getPerformanceData](#mobile-getperformancedata) extension. Available since driver version 2.24\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPerformanceDataTypes > #### Returned Result\n\nList of strings, where each item is data type name.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getClipboard\n\nRetrieves the plaintext content of the device's clipboard. Available since driver version 3.7\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getClipboard > #### Returned Result\n\nBase64-encoded content of the clipboard or an empty string if the clipboard is empty.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: networkSpeed > #### Arguments","sectionCount":9,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setClipboard\n\nAllows to set the plain text content of the device's clipboard. Available since driver version 3.7\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setClipboard > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncontent | string | yes | Base64-encoded clipboard payload. | YXBwaXVt\ncontentType | string | no | The only supported and the default value is `plaintext` | plaintext\nlable | string | no | Optinal label to identify the current clipboard payload. | yolo\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPerformanceData\n\nRetrieves performance data about the given Android subsystem. The data is parsed from the output of the dumpsys utility. Available since driver version 2.24\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPerformanceData > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\npackageName | string | yes | The name of the package identifier to fetch the data for | com.myapp\ndataType | string | yes | One of supported subsystem names. The full list of supported values is returned by [mobile: getPerformanceDataTypes](#mobile-getperformancedatatypes) extension. | batteryinfo or cpuinfo or memoryinfo or networkinfo","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setClipboard","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPerformanceData > #### Returned Result\n\nThe output depends on the selected subsystem. It is organized into a table, where the first row represents column names and the following rows represent the sampled data for each column.\nExample output for different data types:\n\n- batteryinfo:\n```\n[\n [power],\n [23]\n]\n```\n- memoryinfo:\n```\n[\n [totalPrivateDirty, nativePrivateDirty, dalvikPrivateDirty, eglPrivateDirty, glPrivateDirty, totalPss, nativePss, dalvikPss, eglPss, glPss, nativeHeapAllocatedSize, nativeHeapSize],\n [18360, 8296, 6132, null, null, 42588, 8406, 7024, null, null, 26519, 10344]\n]\n```\n- networkinfo:\n```\n// emulator\n[\n [bucketStart, activeTime, rxBytes, rxPackets, txBytes, txPackets, operations, bucketDuration],\n [1478091600000, null, 1099075, 610947, 928, 114362, 769, 0, 3600000],\n [1478095200000, null, 1306300, 405997, 509, 46359, 370, 0, 3600000]\n]\n// real devices\n[\n [st, activeTime, rb, rp, tb, tp, op, bucketDuration],\n [1478088000, null, null, 32115296, 34291, 2956805, 25705, 0, 3600],\n [1478091600, null, null, 2714683, 11821, 1420564, 12650, 0, 3600],\n [1478095200, null, null, 10079213, 19962, 2487705, 20015, 0, 3600],\n [1478098800, null, null, 4444433, 10227, 1430356, 10493, 0, 3600]\n]\n```\n- cpuinfo:\n```\n[\n [user, kernel],\n [0.9, 1.3]\n]\n```\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: statusBar\n\nPerforms commands on the system status bar. A thin wrapper over `adb shell cmd statusbar` CLI. Works on Android 8 (Oreo) and newer. Available since driver version 2.25\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: statusBar > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncommand | string | yes | One of [supported status bar commands](#status-bar-commands). | expandNotifications\ncomponent | string | no | The name of the tile component. It is only required for (add\\|remove\\|click)Tile commands. | com.package.name/.service.QuickSettingsTileComponent","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getPerformanceData > #### Returned Result","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: statusBar > #### Status Bar Commands\n\n- expandNotifications: Open the notifications panel.\n- expandSettings: Open the notifications panel and expand quick settings if present.\n- collapse: Collapse the notifications and settings panel.\n- addTile: Add a TileService of the specified component.\n- removeTile: Remove a TileService of the specified component.\n- clickTile: Click on a TileService of the specified component.\n- getStatusIcons: Returns the list of status bar icons and the order they appear in. Each list item is separated with a new line character.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: statusBar > #### Returned Result\n\nThe actual downstream command output. It depends on the selected command and might be empty.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: scheduleAction\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: unscheduleAction\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getActionHistory\n\nThese extensions allow to deal with short-living UI elements. Read [the documentation on Scheduled Actions](docs/scheduled-actions.md) for more details and code examples.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: screenshots\n\nRetrieves a screenshot of each display available to Android.\nThis functionality is only supported since Android 10.\n\n**Important:** This method uses **physical or virtual display IDs**, which are different from logical display IDs used by the `currentDisplayId` setting. Display IDs can be obtained from:\n- The `physicalId` or `virtualId` field returned by [`mobile: listDisplays`](#mobile-listdisplays) (recommended)\n- The `physicalDisplayId` or `virtualDisplayId` field returned by [`mobile: listWindows`](#mobile-listwindows)\n- The `adb shell dumpsys SurfaceFlinger --display-id` command output\n\n**Note:** For physical displays, use the `physicalId` from `mobile: listDisplays` or `physicalDisplayId` from `mobile: listWindows`. For virtual displays, use the `virtualId` from `mobile: listDisplays` or `virtualDisplayId` from `mobile: listWindows`.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: statusBar > #### Status Bar Commands","sectionCount":6,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: screenshots > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ndisplayId | number or string | no | **Physical or virtual display identifier** to take a screenshot for. If not provided then screenshots of all displays are going to be returned. If no matches were found then an error is thrown. **Note:** This is a physical or virtual display ID, not a logical display ID. Use `mobile: listDisplays` to get the correct `physicalId` (for physical displays) or `virtualId` (for virtual displays) value. | 1234567890\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: screenshots > #### Returns\n\nA dictionary where each key is the physical or virtual display identifier (as a string) and the value has the following keys:\n- `id`: The physical or virtual display identifier (same as the key)\n- `name`: Display name\n- `isDefault`: Whether this display is the default one\n- `payload`: The actual PNG screenshot data encoded to base64 string\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setUiMode\n\nSet the device UI appearance. A thin wrapper over `adb shell cmd uimode` CLI.\nWorks on Android 10 and newer. Available since driver version 2.34\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: setUiMode > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nmode | string | yes | One of the supported UI mode names: `night` or `car`. | night\nvalue | string | yes | The actual mode value to set. Supported values for different UI modes are: `night`: yes,no,auto,custom_schedule,custom_bedtime, `car`: yes,no. For example, to switch the device UI to the dark mode you should set `mode` to `night` and `value` to `yes`, or to `no` in order to switch back to the light mode. | yes\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getUiMode\n\nGets the device UI appearance for the given mode. A thin wrapper over `adb shell cmd uimode` CLI. Works on Android 10 and newer. Available since driver version 2.34\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getUiMode > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nmode | string | yes | One of the supported UI mode names: `night` or `car`. | night","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: screenshots > #### Arguments","sectionCount":6,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getUiMode > #### Returned Result\n\nThe actual mode value. Supported values for different UI modes are:\n\n- `night`: yes,no,auto,custom_schedule,custom_bedtime\n- `car`: yes,no\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: sendTrimMemory\n\nSimulates the [onTrimMemory()](https://developer.android.com/reference/android/content/ComponentCallbacks2#onTrimMemory(int)) event for the given package, which allows to verify the app functinality under different RAM-related circumstances.\nRead [Manage your app's memory](https://developer.android.com/topic/performance/memory) for more details.\nAvailable since driver version 2.41\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: sendTrimMemory > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\npkg | string | yes | The package name to send the `trimMemory` event to. | com.my.company\nlevel | 'COMPLETE' or 'MODERATE' or 'BACKGROUND' or 'UI_HIDDEN' or 'RUNNING_CRITICAL' or 'RUNNING_LOW' or 'RUNNING_MODERATE' | yes | The actual memory trim level to simulate | RUNNING_CRITICAL\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: injectEmulatorCameraImage\n\nSimulates an image injection into the VirtualScene emulator camera background.\nCalls to this extension should seamlessly change the foreground picture\nin the VirtualScene emulator camera view to the supplied one.\nThis extension could, for example, be useful if you need to verify QR codes scanning\nby the application under test.\nAvailable since driver version 3.2.0\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: injectEmulatorCameraImage > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\npayload | string | yes | A valid base64-encoded .PNG image payload. Other image formats are not supported. This image will be shown on the virtual scene foreground as soon as you open a camera client app. | iVBORw0KGgoAAAANSUh...","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: getUiMode > #### Returned Result","sectionCount":5,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: injectEmulatorCameraImage > #### Required Preconditions\n\nThis feature only works on Android emulators.\nIt is mandatory to provide a value (it could also be an empty map to use defaults) to\nthe [appium:injectedImageProperties capability](#emulator-android-virtual-device)\nin order to prepare the emulator for image injection if this extension is used\non a newly created or resetted device.\n\nThere is also a possiblity to perform a manual configuration of the necessary preconditions\nif you don't want to restart the emulator on session startup. For that replace the content\nof the `Toren1BD.posters` file located in `$ANDROID_HOME/emulator/resources` folder with the\nfollowing text:\n\n```\nposter wall\nsize 2 2\nposition -0.807 0.320 5.316\nrotation 0 -150 0\ndefault poster.png\n\nposter table\nsize 1 1\nposition 0 0 -1.5\nrotation 0 0 0\n```\n\nSave the changed file and re(start) the emulator to pick up the changes.\nYou may also customize values for different image properties under `poster table` in the above\ntext snippet.\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: bluetooth\n\nAllows to control the bluetooth adapter in the device under test.\nAn error is thrown if the device has no default bluetooth adapter.\nAvailable since driver version 3.4.0\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: bluetooth > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\naction | string | yes | The action to execute on the bluetooth adapter. The following actions are supported: `enable`, `disable`, `unpairAll`. Calling the same action more than once is a noop. | disable\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: nfc\n\nAllows to control the NFC adapter in the device under test.\nAn error is thrown if the device has no default NFC adapter.\nAvailable since driver version 3.4.0\n\n# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: nfc > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\naction | string | yes | The action to execute on the NFC adapter. The following actions are supported: `enable`, `disable`. Calling the same action more than once is a noop. | disable","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Platform-Specific Extensions > ### mobile: injectEmulatorCameraImage > #### Required Preconditions","sectionCount":5,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Applications Management\n\nUiAutomator2 driver supports Appium endpoints for applications management:\n- Check if app is installed ([mobile: isAppInstalled](#mobile-isappinstalled))\n- Lists all installed packages ([mobile: listApps](#mobile-listapps))\n- Install/upgrade app ([mobile: installApp](#mobile-installapp))\n- Activate app ([mobile: activateApp](#mobile-activateapp))\n - Since UIAutomator2 driver v2.2.0, the server calls `am start`/`am start-activity` to start the application on devices with API level 24+. [monkey](https://developer.android.com/studio/test/other-testing-tools/monkey) tool is called on devices below API level 24.\n - UIAutomator2 driver v2.1.2 and lower versions call the `monkey` tool on all devices.\n - The `monkey` tool [turns on auto rotation](https://stackoverflow.com/questions/56684778/adb-shell-monkey-command-changing-device-orientation-lock), so please consider using [mobile: startActivity](#mobile-startactivity) if you would like to keep your current rotation preferences.\n- Uninstall app ([mobile: removeApp](#mobile-removeapp))\n- Terminate app ([mobile: terminateApp](#mobile-terminateapp))\n- Start app activity ([mobile: startActivity](#mobile-startactivity))\n- Query the current app state ([mobile: queryAppState](#mobile-queryappstate))\n- Background app ([mobile: backgroundApp](#mobile-backgroundapp))\n\nRefer to the corresponding Appium client tutorial to find out the names of the corresponding wrappers for these APIs.\n\nUseful links:\n- https://appiumpro.com/editions/9-testing-android-app-upgrades\n- https://github.com/appium/python-client/blob/master/appium/webdriver/extensions/applications.py\n- https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/InteractsWithApps.java\n\n# Appium UiAutomator2 Driver > ## Files Management\n\nUiAutomator2 driver supports Appium endpoints for files management:\n- Push file ([mobile: pushFile](#mobile-pushfile))\n- Pull file ([mobile: pullFile](#mobile-pullfile))\n- Pull folder ([mobile: pullFolder](#mobile-pullfolder))\n\nRefer to the corresponding Appium client tutorial to find out the names of the corresponding wrappers for these APIs.\n\nUseful links:\n- https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/PushesFiles.java\n- https://github.com/appium/python-client/blob/master/appium/webdriver/extensions/remote_fs.py","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Applications Management","sectionCount":2,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Clipboard Management\n\nUiAutomator2 driver supports Appium endpoints for clipboard management:\n- Set clipboard content (`POST /appium/device/set_clipboard'`)\n- Get clipboard content (`POST /appium/device/get_clipboard`)\n- [mobile: getClipboard](#mobile-getclipboard)\n- [mobile: setClipboard](#mobile-setclipboard)\n\nUseful links:\n- https://github.com/appium/python-client/blob/master/appium/webdriver/extensions/clipboard.py\n- https://github.com/appium/java-client/blob/master/src/main/java/io/appium/java_client/clipboard/HasClipboard.java\n- https://appiumpro.com/editions/16-automating-the-clipboard-on-ios-and-android","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Clipboard Management","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Hybrid Mode\n\nUIA2 driver supports automation of web pages opened in mobile Chrome or Chromium, and\nhybrid apps that use Chrome-based web views, by managing a\n[Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/) instance and\nproxying commands to it when necessary.\n\nThe following endpoints are used to control the current context:\n\n- POST `/session/:sessionId/context`: To set the current context. The body contains a single mandatory `name` parameter, which has the name of the context to be set. The name of the default context is `NATIVE_APP`.\n- GET `/session/:sessionId/context`: To retrieve the name of the current context\n- GET `/session/:sessionId/contexts`: To retrieve the list of available context names\n- [mobile: getContexts](#mobile-getcontexts)\n- [mobile: getChromeCapabilities](#mobile-getchromecapabilities)\n\nBy default, the driver starts in the native context, which means that most of REST API commands are being\nforwarded to the downstream [appium-uiautomator2-server](https://github.com/appium/appium-uiautomator2-server).\nThis server is running on the device under test, and trasforms API commands to appropriate low-level UiAutomator framework calls. There is always only one native context, although multiple web contexts are possible.\nEach web context could contain zero or more pages/windows. It is possible to start UIA2 driver session in web context by default by setting the `browserName` capability value or by enabling the `appium:autoWebview` capability.\n\nWeb context(s) could be detected if a browser or a web view is active on the device. If a context is switched to\na web one then UIA2 driver spins up a Chromedriver instance for it and forwards most of the commands\nto that Chromedriver instance. Note that web views must be properly configured and\ndebuggable in order to connect to them or get their names in the list of available contexts.\nThe availability of a particular web view could be easily verified by using\n[Chrome Remote Debugger](https://developer.chrome.com/docs/devtools/remote-debugging/).\nYou could switch between different contexts (and windows in them) at any time during the session.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Hybrid Mode","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Hybrid Mode\n\nThe [appium-chromedriver](https://github.com/appium/appium-chromedriver) package bundled with UIA2 always\ntries to download the most recent version of Chromedriver known to it. Google requires that the used Chromedriver version must always match to the version of the browser or a web view engine being automated. If these versions do not match then Chromedriver fails its creation, and context switch API shows a failure message\nsimilar to:\n\n```\nAn unknown server-side error occurred while processing the command.\nOriginal error: unknown error: Chrome version must be >= 55.0.2883.0\n```\n\nTo work around this issue it is necessary to provide UIA2 driver with a proper Chromedriver binary\nthat matches to the Chrome engine version running on the device under test.\nRead the [Chromedriver/Chrome compatibility](#chromedriverchrome-compatibility) topic below to\nknow more about finding a matching Chromedriver executable.\n\nThere are several ways to provide a customized Chromedriver to UIA2 driver:","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Hybrid Mode","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Hybrid Mode > #### When installing the driver\n\n_Note_: This only works for driver versions below 3.8.0\n\nSpecify the Chromedriver version in the `CHROMEDRIVER_VERSION` environment variable:\n\n```bash\nCHROMEDRIVER_VERSION=2.20 appium install driver uiautomator2\n```\n\n# Appium UiAutomator2 Driver > ## Hybrid Mode > #### When starting a session (manual discovery)\n\nChromedriver version can be specified in session capabilities, by providing the\n`appium:chromedriverExecutable` [capability](#web-context),\ncontaining the full path to a matching Chromedriver executable, which must be manually\ndownloaded and put to the server file system.\n\n# Appium UiAutomator2 Driver > ## Hybrid Mode > #### When starting a session (automated discovery)\n\nUIA2 driver could also try to detect the version of the target Chrome engine and\ndownload matching chromedriver for it automatically if it does not exist on the local file system.\nRead the [Automatic discovery of compatible Chromedriver](#automatic-discovery-of-compatible-chromedriver)\ntopic below for more details.\n\n# Appium UiAutomator2 Driver > ## Hybrid Mode > ### Chromedriver/Chrome Compatibility\n\nSince version *2.46* Google has changed their rules for Chromedriver versioning, so now the major Chromedriver version corresponds to the major web view/browser version, that it can automate. Follow the [Version Selection](https://chromedriver.chromium.org/downloads/version-selection) document in order to manually find the Chromedriver, that supports your current browser/web view if its major version is equal or above *73*.\n\nTo find the minimum supported browsers for older Chromedriver versions (below *73*), get the\n[Chromium](https://www.chromium.org/Home)\n[source code](https://chromium.googlesource.com/chromium/src/+/master/docs/get_the_code.md),\ncheck out the release commit, and check the variable `kMinimumSupportedChromeVersion`\nin the file `src/chrome/test/chromedriver/chrome/version.cc`. (To find the\nrelease commits, you could use `git log --pretty=format:'%h | %s%d' | grep -i \"Release Chromedriver version\"`.)\n\nThe complete list of available Chromedriver releases and release notes is located at [Chromedriver Storage](https://chromedriver.storage.googleapis.com/index.html).\n\nThe list of Chromedriver versions and their matching minimum\nChrome versions known to appium-chromedriver package is stored at\nhttps://raw.githubusercontent.com/appium/appium-chromedriver/master/config/mapping.json","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Hybrid Mode > #### When installing the driver","sectionCount":4,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Hybrid Mode > ### Automatic Discovery of Compatible Chromedriver\n\nUIA2 driver is able to pick the correct Chromedriver for the\nversion of Chrome/web view under test. While appium-chromedriver only comes bundled with the Chromedriver\nmost recently released at the time of the corresponding package version's release, more Chromedriver\nversions could be downloaded and placed into a custom location indicated to UIA2 driver via the `appium:chromedriverExecutableDir` [capability](#web-context).\n\nA custom mapping of Chromedrivers to the minimum\nChrome/web view version they support could be given to UIA2 driver through the\n`appium:chromedriverChromeMappingFile` [capability](#web-context). This should be the\nabsolute path to a file with the mapping\nin it. The contents of the file needs to be parsable as a JSON object, like:\n\n```json\n{\n \"2.42\": \"63.0.3239\",\n \"2.41\": \"62.0.3202\"\n}\n```\n\nThere is a possibility to automatically download the necessary chromedriver(s) into `appium:chromedriverExecutableDir` from the official Google storage. The script will automatically search for the newest chromedriver version that supports the given browser/web view, download it (the hash sum is verified as well for the downloaded archive) and add to the `appium:chromedriverChromeMappingFile` mapping. Everything, which is needed to be done from your side is to execute the server with `uiautomator2:chromedriver_autodownload` feature enabled (like `appium server --allow-insecure uiautomator2:chromedriver_autodownload`).\n\n# Appium UiAutomator2 Driver > ## Hybrid Mode > ### Troubleshooting Chromedriver Download Issues\n\nCheck the [Custom binaries url](https://github.com/appium/appium-chromedriver?tab=readme-ov-file#custom-binaries-url)\nsection of appium-chromedriver README for more details on how to customize the download CDN.\n\nIt may also be necessary to adjust network proxy and firewall settings for the above to work.\n\nIf you use a UIA2 driver below version 3.8.0, and you\nwould like skip the automated download of Chromedriver upon driver install, do it by\ndefining the `APPIUM_SKIP_CHROMEDRIVER_INSTALL` environment variable:\n\n```bash\nAPPIUM_SKIP_CHROMEDRIVER_INSTALL=1 appium driver install uiautomator2\n```","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Hybrid Mode > ### Automatic Discovery of Compatible Chromedriver","sectionCount":2,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Hybrid Mode > ### W3C Support in Web Context\n\nChromedriver did not follow the W3C standard until version 75. If you encounter proxy command error like [this issue](https://github.com/appium/python-client/issues/234), please update your Chromedriver version.\nOld Android devices can't use newer Chromedriver versions. You could avoid the error if you enforce\nMobile JSON Wire Protocol for Chromedriver. This could be done by providing `{'w3c': False}` item\nto `appium:chromeOptions` capability value.\nSince major version *75* W3C mode is the default one for Chromedriver, although it could be still switched to JSONWP one as described above (keep in mind that eventually Chromedriver will drop the support of\nJSON Wire protocol completely).\nThe history of W3C support in Chromedriver is available for reading at\n[downloads section](https://sites.google.com/a/chromium.org/chromedriver/downloads).\n\n# Appium UiAutomator2 Driver > ## Troubleshooting\n\n# Appium UiAutomator2 Driver > ## Troubleshooting > ### Activity Startup\n\nIf you experience issues with application activities being not found or not starting then consider checking [How To Troubleshoot Activities Startup](docs/activity-startup.md) article.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Hybrid Mode > ### W3C Support in Web Context","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### Poor Elements Interaction Performance\n\nIf you observe automated tests need at least 10 seconds or more to locate/interact with a single element then consider changing the default value for [waitForIdleTimeout setting](#settings-api). By default, UiAutomator framework (and all other Accessibility-based frameworks) always waits for the accessibility event stream to become idle before interacting with it (the default timeout there is 10000ms). This is needed to make sure all animations/transitions are finished before you, for example, interact with an element by clicking it. In case the application under test constantly runs some background animations or hogs the accessibility event stream in some other way these waits may significantly slow down the automation flow.\n\nSetting the value of `waitForIdleTimeout` to zero `0` ms should completely disable any waits, and enforce interactions to happen immediately ignoring the accessibility event stream state. The downside of that would be that all interactions are never going to be delayed, so clicks and other actions might happen at wrong places of the application UI. That is why is it important to check the app under test first and fix its source to get rid of activities hogging the event loop. Sometimes it makes sence to disable animations completely for the app build under test, which could speed up your flows significantly in some situations.\n\n> [!Warning]\n> `waitForIdleTimeout` is a setting, not a capability.\n\n# Appium UiAutomator2 Driver > ## Troubleshooting > ### Session Startup Issues\n\nSometimes various legacy driver parts might be cached on the device under test (like settings.apk), which would prevent a new/upgraded driver version from starting a session. Run\n\n```bash\nappium driver run uiautomator2 reset\n```\n\nin order to cleanup the cached UIA2 driver binaries from all connected devices on the current machine.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### Poor Elements Interaction Performance","sectionCount":2,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### Socket Hangup Error\n\nThis type of error means the driver is unable to connect to the UiAutomator2 REST server, which is running on the device under test. There might be multiple causes to this issue:\n- The automation session gets unexpectedly deleted if your test code sends the `DELETE /session/<id>` request to it, also the corresponding session and the server itself are terminated as a result. Sending further commands to the same server would create the error above because it is not listening anymore and must be newly started by the instrumentation first. Such issues usually happen if the session management is not configured properly in your code, so one starts a new session while an existing one is still running and has not been quit properly, or there is a timeout while waiting for a new command. Fixing session management logic (e.g. make sure each session is being properly created in the test setup section and is terminated in the test teardown) or changing/disabling the commands' timeout (check the [newCommandTimeout capability](#other)) might help to address such type of errors.\n- The server has been unexpectedly killed by Android OS itself. There might be several reasons to that. Usually fetching the [logcat](https://developer.android.com/studio/command-line/logcat) output and finding occurrences of `io.appium.uiautomator2.server` traces with `error` or `exception` label might help to figure out what happens. Sometimes it is necessary to turn off some internal phone optimizations, sometimes the server crashes because of an internal UiAutomator framework bug, sometimes because of a bug in the server code itself. Each case should be investigated separately if the search over the internet shows no matches…\n- The connectivity between the phone and the host is unstable. Nothing much to add on this one. Maybe the phone has a defect, or the USB cable is damaged, or the installed Android SDK is out of date…","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### Socket Hangup Error","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### Element(s) Cannot be Found\n\nAll element location strategies in UIA2 driver work similarly under the hood except of the xpath one.\nIf some element is not found, but you see/assume it is present in the page source then make sure no race condition\nhappens. Add a timer and wait for a couple of seconds before giving up on the element location. In case the lookup\nstill fails after the timeout and your non-xpath locator is used then, most likely, it contains a typo, or the\ndestination element is not present. There is not much that could be done in UIA2 to change/influence that, since it passes such lookup calls directly to Google's UiAutomator framework.\n\nIn case of _xpath_ locators you could try to change values of the following settings:\n\n1. [allowInvisibleElements](#settings-api)\n2. [ignoreUnimportantViews](#settings-api)\n3. [enableMultiWindows](#settings-api)\n4. [snapshotMaxDepth](#settings-api)\n\nBy default, the first setting is set to `false`, which hides\nelements that are not visible from the page source and from the xpath location. Changing the setting value\nto `true` would add such invisible elements to the page source and make them locatable.\n\nThe second one is enabled by default (e.g. `true`). By disabling it the page source could receive more elements\nthat are normally hidden, because of their unimportance.\n\nThe third setting being set to `true` extends the page source by adding the actual content of other windows that are currently present on the device's screen. For example, the on-screen keyboard in Android is not a part of the current app hierarchy, but rather belongs to a separate window.\n\nIt only makes sense to change the default value of the `snapshotMaxDepth` setting if the application under test\nhas deeply nested elements in the page tree hierarchy (e.g. more than 70 levels), and the destination element\nis suspected to be a part of these deeply nested views. Increasing the value of this\nsetting will reduce the performance of xPath searches and page tree retrievals, so be careful while assigning too\nhigh values to it.\n\nIn case of _id_ locators you could try to change the value of the following setting:\n\n1. [disableIdLocatorAutocompletion](#settings-api)","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### Element(s) Cannot be Found","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### Element(s) Cannot be Found\n\nIn case of _id_ locators you could try to change the value of the following setting:\n\n1. [disableIdLocatorAutocompletion](#settings-api)\n\nThe general resources naming convention for Android apps is `<app_id>:id/<resource_name>`. This should guarantee uniqueness of each identifier accross the user interface. Although, this is only a convention and it is still allowed to have various resource names that do not follow it. If you have gotten one of such applications for automated testing then consider assigning `disableIdLocatorAutocompletion` setting value to `true`, so UiAutomator2 driver does not automatically rewrite supplied id values by adding `<app_id>:id/` prefixes to them.\n\n> [!Warning]\n> Default values for settings above have been selected to optimize xpath lookup and page source generation performance.\n> Having these settings always different from their default values may sometimes significantly (especially in case of huge accessbility hierarchies) reduce xpath lookup and page source generation speed.\n\n> [!Warning]\n> All items above are settings, not capabilities.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### Element(s) Cannot be Found","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### ClassCastException: java.util.ArrayList$ListItr cannot be cast to org.eclipse.wst.xml.xpath2.processor\n\nThis exception happens due to a known bug in the [Eclipse's Psychopath](https://wiki.eclipse.org/PsychoPathXPathProcessor) library used by UiAutomator2 driver to support [XPath2](https://www.w3.org/TR/xpath20/) syntax. The issue has been observed while using `following::` or `preceding::` axes in xpath queries. Unfortunately, this library has not been maintained for quite a while, and there is no good open source alternative to it. The only known workaround would be to forcefully switch the driver's XPath processor to the standard Android's Apache Harmony-based XPath1, which does not have this issue (but also does not support XPath2 syntax). See the Appium issue [#16142](https://github.com/appium/appium/issues/16142#issuecomment-1003954166) for more details.","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### ClassCastException: java.util.ArrayList$ListItr cannot be cast to org.eclipse.wst.xml.xpath2.processor","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### A gesture, like scroll or swipe, does not have any effect / It is unclear how to do it\n\nThe UiAutomator2 driver provides multiple options for touch gestures automation.\nFor simple gestures, like swipe, scroll, drag, double click, fling or pinch use the corresponding\n[gesture shortcuts](#mobile-gesture-commands).\nYou may also use [UiScrollable-based UiAutomator locators](./docs/uiautomator-uiselector.md)\nto automate various scrolling behaviours.\nFor more sophisticated gestures\nconsider using [W3C actions](https://w3c.github.io/webdriver/#actions).\n\n\nMake sure you don't use deprecated JWP touch actions APIs. They have been\nremoved from the UIA2 driver since version 3.\n\nIf the action code in the client source looks good and satisfies the above requirements,\nbut its execution still does not deliver the expected result then the following debugging\nmeassures might be applied:\n\n- Enable `Show taps` and `Pointer location` Developer options in the device Settings. After running\n your automation code with the above options enabled you would be able to see the exact pointer trace path\n and check the velocity of the gesture. It also works for multi-touch gestures. Compare the trace\n to how the same gesture is usually done manually and apply the necessary updates to your code.\n- Check the device [logcat](https://developer.android.com/studio/debug/logcat) output for possible\n error messages. Usually a single gesture consists of hundreds of atomic steps. If any of these steps\n receives incorrect/unsupported parameters then the whole gesture might fail. The log has details\n about each step being executed and arguments passed to it.\n- Make sure the gesture has valid coordinates and respects pauses between pointer state changes.\n For example, it is always mandatory to provide a valid element or valid `absolute` coordinates\n to any gesture at the beginning. Android only registers\n a long touch/click if the pointer has been depressed for longer than 500ms. For shorter actions\n a simple click is registered instead.\n- Do not mix webview and native elements in actions arguments. It simply won't work. Native\n actions could only consume native elements. A single possibility to perform a native action\n on a web element would be to traslate its coordinates into the native context and pass these\n coordinates as native action arguments.\n\nCheck the below tutorials for more details on how to build reliable action chains:","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### A gesture, like scroll or swipe, does not have any effect / It is unclear how to do it","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### A gesture, like scroll or swipe, does not have any effect / It is unclear how to do it\n\nCheck the below tutorials for more details on how to build reliable action chains:\n\n- [Automating Complex Gestures with the W3C Actions API](https://appiumpro.com/editions/29-automating-complex-gestures-with-the-w3c-actions-api)\n- [Swiping your way through Appium by Wim Selles #AppiumConf2021](https://www.youtube.com/watch?v=oAJ7jwMNFVU)\n- [Low-Level Insights on Android Input Events](./docs/actions.md)","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### A gesture, like scroll or swipe, does not have any effect / It is unclear how to do it","sectionCount":1,"recursiveSplit":true,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### window/tab hanlding in WEBVIEW context implemented by chrome custom tabs\n\n[Chrome custom tabs](https://developer.chrome.com/docs/android/custom-tabs/) could have its own window handlings as same as regular Selenium Web automation.\n\nAppium lets you switch the context from `NATIVE_APP` to `WEBVIEW_xyz`, for example, to interact with the WEBVIEW contents over chromedriver. Then, if the WEBVIEW was chrome custom tabs implementation, the WEBVIEW context may require you to switch the window handler properly to interact with contents in a handler.\nIt is worth to try out this idea if `chrome://inspect` or [mobile: getContexts](#mobile-getcontexts) shows you available pages more than availale contexts.\n\n```ruby\n# Ruby\n# Change the context to WebView (Attach to a chromedriver session)\ndriver.set_context('WEBVIEW_XYZ')\n\n# Get available tabs/windows in the chrome instance\ndriver.window_handles\n\n# Change the tab/window in the \"chrome\" instance\ndriver.switch_to.window('a window_handle name')\n\n# interact with the tab/window\n```","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Troubleshooting > ### window/tab hanlding in WEBVIEW context implemented by chrome custom tabs","sectionCount":1,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"# Appium UiAutomator2 Driver > ## Usage Examples\n\n```python\n# Python3 + PyTest\nimport pytest\n\nfrom appium import webdriver\n# Options are available in Python client since v2.6.0\nfrom appium.options.android import UiAutomator2Options\n\n\ndef generate_options():\n common_caps = {\n # A real device udid could be retrieved from `adb devices -l` output\n # If it is ommitted then the first available device will be used\n 'appium:udid': '123456',\n # ...or run the test on an emulator\n # 'appium:avd': 'emulator-5554',\n }\n app_options = UiAutomator2Options().load_capabilities(common_caps)\n app_options.app = '/Projects/myapp.apk'\n # It might also be necessary to provide more info about app activities\n # Read [How To Troubleshoot Activities Startup](docs/activity-startup.md)\n # for more details\n # app_options.appPackage = 'com.mypackage'\n # app_options.appActivity = '.myMainActivity'\n # app_options.appWaitActivity = '.mySplashScreenActivity'\n chrome_options = UiAutomator2Options().load_capabilities(common_caps)\n chrome_options.browser_name = 'chrome'\n # Read [Hybrid Mode](#hybrid-mode)\n chrome_options.chromedriver_executable = '/Project/chromedriver_linux64'\n return [app_options, chrome_options]\n\n\n@pytest.fixture(params=generate_options())\ndef driver(request):\n # The default URL is http://127.0.0.1:4723/wd/hub in Appium1\n drv = webdriver.Remote('http://localhost:4723', options=request.param)\n yield drv\n drv.quit()\n\n\ndef test_edit_text(driver):\n locator = 'android.view.TextEdit' if driver.current_context == 'NATIVE_APP' else 'input'\n edit_field = driver.find_element_by_class_name(locator)\n edit_field.send_keys('hello world')\n assert edit_field.text == 'hello world'\n edit_field.clear()\n assert edit_field.text == ''\n\n```\n\n# Appium UiAutomator2 Driver > ## API Notes\n\n`lock` behaves differently in Android than it does in iOS. In Android it does not take any arguments, and locks the screen and returns immediately.\n\n# Appium UiAutomator2 Driver > ## Development\n\n```\nnpm install appium-uiautomator2-driver\nnpm run dev\n```\n\nUnit tests:\n\n```\nnpm run test\n```\n\nFunctional tests:\n\n```\nnpm run e2e-test:commands\nnpm run e2e-test:commands:find\nnpm run e2e-test:commands:general\nnpm run e2e-test:commands:keyboard\nnpm run e2e-test:driver\n```","metadata":{"headerPath":"# Appium UiAutomator2 Driver > ## Usage Examples","sectionCount":3,"filename":"README.md","relativePath":"appium-uiautomator2-driver/README.md"}},{"pageContent":"## Low-Level Insights on Android Input Events\n\n## Low-Level Insights on Android Input Events > ### What Are Input Events\n\nAndroid OS uses events concept to handle signals received from different input devices.\nIt supports a wide range of different devices, such as touch screen, light pen, mouse, keyboard,\nbut most of them are using [MotionEvent](https://developer.android.com/reference/android/view/MotionEvent) or [KeyEvent](https://developer.android.com/reference/android/view/KeyEvent) APIs, which are derived from the base [InputEvent](https://developer.android.com/reference/android/view/InputEvent) class. These APIs are quite flexible and support a wide range of different settings.\nWe are particularly interested in the part of these APIs, which are responsible for touch and\nkeyboard events generation/emulation.\n\n## Low-Level Insights on Android Input Events > ### How Input Events Are Working\n\nAn event is an object, which is generated in response to a signal from an input device.\nThese objects are then delivered to the corresponding kernel subsystem, which processes them\nand notifies all listening processes about taps, key presses, swipes, etc.\nThis means that in order to emulate a signal generated by\nan external device, such as touch screen, it is necessary to just send event objects with\nthe same properties and in the same sequence as they would be generated by a real device.","metadata":{"headerPath":"## Low-Level Insights on Android Input Events","sectionCount":3,"filename":"actions.md","relativePath":"appium-uiautomator2-driver/docs/actions.md"}},{"pageContent":"## Low-Level Insights on Android Input Events > ### Lets Simulate a Single Tap\n\nEach input device has a set of actions whose property ranges and sequences are already predefined\nin the operating system. These actions we call \"tap\", \"swipe\" or \"double tap\", etc. The properties\nof each action could be found either in the Android documentation or in the OS source code.\nIn order to perform events sequence, which is recognized as single tap, it is necessary to generate\nthe following motion events:\n - `ACTION_POINTER_DOWN`\n - wait 125ms (525ms or longer wait will synthesize a long tap action instead)\n - `ACTION_POINTER_UP`. The `downTime` property should be set to the same timestamp as for `ACTION_POINTER_DOWN`\n\nIt is also important, that coordinates and other properties of both the starting and the closing event should be equal except of the `eventTime` one, which is always equal to the current system timestamp in milliseconds (`SystemClock.uptimeMillis()`).\nThe `MotionEvent` object itself could be created via [obtain](https://developer.android.com/reference/android/view/MotionEvent#obtain(long,%20long,%20int,%20float,%20float,%20int)) API, where parameters are the corresponding event properties.\n\nAfter events are created they must be passed to the system for execution.\nSuch action is not secure, so it is only possible in instrumented tests via [injectInputEvent](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/IUiAutomationConnection.aidl) method of `IUiAutomationConnection` interface.\nThis is a very low-level method and it can only be accessed via reflection in automated tests.\nNormally, UiAutomator APIs have wrappers over it (like `touchDown`, `touchMove`, etc.), that already simulate the stuff described above.","metadata":{"headerPath":"## Low-Level Insights on Android Input Events > ### Lets Simulate a Single Tap","sectionCount":1,"filename":"actions.md","relativePath":"appium-uiautomator2-driver/docs/actions.md"}},{"pageContent":"## Low-Level Insights on Android Input Events > ### How About More Complicated Actions\n\nIn theory it is possible to emulate any input action using a generated events sequence.\nAlthough, some actions, like multi-finger swipe,\nare really complicated and require a lot of events to be generated\nwith correct properties and timings. The OS simply ignores given events if they don't follow\ninternal action requirements. There is also a little assistance from UiAutomator framework,\nbecause Google only has wrappers for a limited set of simple actions, like `tap`, `drag` or `swipe`.\nSo, in order to generate two-finger symmetric swipe we need to supply the following events chain:\n - `ACTION_POINTER_DOWN` (finger1)\n - `ACTION_POINTER_DOWN` (finger2)\n - start a loop, that generates `ACTION_POINTER_MOVE` event each `20ms` for both `finger1` and `finger2` until `ACTION_POINTER_UP` is performed. The `downTime` should be set to the same timestamp as for the corresponding `ACTION_POINTER_DOWN`. The coordinates of each move event should be points belonging to the path between the corresponding start and end point coordinates normalized by the current timestamp (x0 + sqrt(sqr(x0) + sqr(x1))) * k, y0 + sqrt(sqr(y0) + sqr(y1))) * k).\n - `ACTION_POINTER_UP` (finger1) The `downTime` property should be set to the same timestamp as for the corresponding `ACTION_POINTER_DOWN`\n - `ACTION_POINTER_UP` (finger2) The `downTime` property should be set to the same timestamp as for the corresponding `ACTION_POINTER_DOWN`\n\nGoogle uses 5ms as interval duration between move events in UiAutomator code,\nbut according to our observations this value is too little,\nwhich causes noticeable delays in actions execution.","metadata":{"headerPath":"## Low-Level Insights on Android Input Events > ### How About More Complicated Actions","sectionCount":1,"filename":"actions.md","relativePath":"appium-uiautomator2-driver/docs/actions.md"}},{"pageContent":"## Low-Level Insights on Android Input Events > ### Further Reading\n\nUnfortunately, there is no so much detailed information on this topic. The only reliable source\nof the information are Android OS sources themselves. Consider visiting the following resources:\n\n- https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewConfiguration.java\n- https://android.googlesource.com/platform/frameworks/uiautomator/+/refs/heads/master\n- https://github.com/appium/appium-uiautomator2-server/tree/master/app/src/main/java/io/appium/uiautomator2/utils/w3c\n- https://github.com/appium/appium-uiautomator2-server/tree/master/app/src/test/java/io/appium/uiautomator2/utils/w3c\n- https://github.com/appium/appium-espresso-driver/tree/master/espresso-server/library/src/main/java/io/appium/espressoserver/lib/helpers/w3c","metadata":{"headerPath":"## Low-Level Insights on Android Input Events > ### Further Reading","sectionCount":1,"filename":"actions.md","relativePath":"appium-uiautomator2-driver/docs/actions.md"}},{"pageContent":"## How To Troubleshoot Activities Startup\n\n## How To Troubleshoot Activities Startup > ### Capabilities\n\n> The Activity class is a crucial component of an Android app, and the way activities are launched and put together is a fundamental part of the platform's application model. Unlike programming paradigms in which apps are launched with a main() method, the Android system initiates code in an Activity instance by invoking specific callback methods that correspond to specific stages of its lifecycle.\n> &copy; [Android Developer Documentation](https://developer.android.com/guide/components/activities/intro-activities)\n\nAppium needs to know package and activity names in order to properly initialize the application under test. This information is expected to be provided in driver capabilities and consists of the following keys:\n\n- `appActivity`: The name of the main application activity\n- `appPackage`: The identifier of the application package\n- `appWaitActivity`: The name of the application activity to wait for/which starts the first\n- `appWaitPackage`: The id of the application package to wait for/which starts the first\n- `appWaitDuration`: The maximum duration to wait until the `appWaitActivity` is focused in milliseconds (20000 by default)\n- `appWaitForLaunch`: Whether to wait until Activity Manager returns the control to the calling process. By default the driver always waits until `appWaitDuration` is expired. Setting this capability to `false` effectively cancels this wait and unblocks the server loop as soon as `am` successfully triggers the command to start the activity.\n\nAll these capabilities are optional. If they are not set explicitly then Appium tries to auto detect them by reading their values from the APK manifest. Although, if the application under test is supposed to be already installed on the device (`noReset=true`) then at least `appActivity` and `appPackage` options are required to be set, since no package manifest is available in such case. If you don't set `appWaitPackage` and `appWaitActivity` explicitly then these are getting assigned to `appPackage`/`appActivity` values automatically. For more details check on the implementation of `packageAndLaunchActivityFromManifest` method in the [appium-adb](https://github.com/appium/appium-adb/blob/master/lib/tools/android-manifest.js) package.","metadata":{"headerPath":"## How To Troubleshoot Activities Startup","sectionCount":2,"filename":"activity-startup.md","relativePath":"appium-uiautomator2-driver/docs/activity-startup.md"}},{"pageContent":"## How To Troubleshoot Activities Startup > ### How Appium Starts Activities\n\nActivities are started by [Call activity manager `am`](https://developer.android.com/studio/command-line/adb#am). Appium tries to start the `appPackage`/`appActivity` combination using `am start` and then waits until the `appWaitPackage`/`appWaitActivity` is focused or the `appWaitDuration` timeout expires. The currently focused activity name is parsed from `adb shell dumpsys window windows` command output (`mFocusedApp` or `mCurrentFocus` entries). For more details check on the implementation of `startApp`, and `getFocusedPackageAndActivity` methods in the [appium-adb](https://github.com/appium/appium-adb/blob/master/lib/tools/apk-utils.js) package.\n\n## How To Troubleshoot Activities Startup > ### Possible Problems And Solutions\n\n## How To Troubleshoot Activities Startup > ### Possible Problems And Solutions > #### java.lang.SecurityException: Permission Denial: starting Intent\n\nThe full error description usually looks like `'java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.mypackage/.myactivity.MainActivity launchParam=MultiScreenLaunchParams { mDisplayId=0 mBaseDisplayId=0 mFlags=0 } } from null (pid=11366, uid=2000) not exported from uid 10191`. Such error might be the indication of the fact that the combination of application package and activity name, which has been passed to Appium as `appPackage`/`appActivity` (or auto detected implicitly), is not the correct one to start the application under test. As a solution, it is necessary to check the correct values with the application developer and test them manually first by executing: `adb shell am start -W -n com.myfixedpackage/.myfixedactivity.MainActivity -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000`. If this commands succeeds manually and starts the necessary application on the device then it will work for Appium as well.\n\nSome devices might require customization of the security configuration in the developer options, or security preferences. For example, Realme devices require [_Disable Permission Monitoring_ and a couple of flags in the developer options](https://github.com/appium/appium/issues/13802#issuecomment-702789411) to avoid the _Permission Denial_ error.","metadata":{"headerPath":"## How To Troubleshoot Activities Startup > ### How Appium Starts Activities","sectionCount":3,"filename":"activity-startup.md","relativePath":"appium-uiautomator2-driver/docs/activity-startup.md"}},{"pageContent":"## How To Troubleshoot Activities Startup > ### Possible Problems And Solutions > #### com.myactivity or com.myapp.com.myactivity never started\n\nThis exception usually indicates, that the first application activity is not the same package/activity, as it is set (or auto detected) by `appWaitPackage`/`appWaitActivity`. Such error normally happens in applications having multiple activities. In order to resolve the problem one should check with application developer regarding which activity/package is the very first one that appears on application startup. The currently focused activity name might be verified using the `adb shell dumpsys window windows` command mentioned above. Also, Appium allows to use wildcards while setting `appWaitActivity` value. This might be particularly useful if the activity name is generated dynamically or it is not the same all the time. For example `com.mycomany.*` will match any of `com.mycomany.foo`, `com.mycomany.bar`.\n\n## How To Troubleshoot Activities Startup > ### Possible Problems And Solutions > #### Command '…' timed out after X ms\n\nIf you've double checked that activity names are correct, but the startup still times out, then try to increase the value of `appWaitDuration` capability. Normally, the default 20 seconds is enough for the most of applications, however, some bigger apps might require more time to start and show the first activity. Please, don't create such apps.\n\nThere might be also situations where an activity does not return the control to the calling process at all, so `am start` call blocks forever independently of the value of `appWaitDuration`, thus causing the timeout. In such case setting `appWaitForLaunch` to `false` might help to resolve the issue. Although, by choosing this option, the driver cannot make sure the activity has fully started, so then it is up to the client code to verify the initial UI state is the one that is expected.","metadata":{"headerPath":"## How To Troubleshoot Activities Startup > ### Possible Problems And Solutions > #### com.myactivity or com.myapp.com.myactivity never started","sectionCount":2,"filename":"activity-startup.md","relativePath":"appium-uiautomator2-driver/docs/activity-startup.md"}},{"pageContent":"## How To Troubleshoot Activities Startup > ### Possible Problems And Solutions > #### java.util.concurrent.ExecutionException: com.google.firebase.installations.FirebaseInstallationsException\n\n`firebaseinstallations.googleapis.com` sends the apk's certificate information as the header `X-Android-Cert` in its initialization step. Appium UiAutomator2 driver resigns the application under test with the default Appium debug signature. It causes an exception, `java.util.concurrent.ExecutionException: com.google.firebase.installations.FirebaseInstallationsException`, when the application under test starts. To avoid the exception, the session must have `noSign: true` capability to avoid re-signing. [Unblocking Firebase Network Traffic in Modified Android Applications](https://www.thecobraden.com/posts/unblocking_firebase_ids/) explains the cause more.","metadata":{"headerPath":"## How To Troubleshoot Activities Startup > ### Possible Problems And Solutions > #### java.util.concurrent.ExecutionException: com.google.firebase.installations.FirebaseInstallationsException","sectionCount":1,"filename":"activity-startup.md","relativePath":"appium-uiautomator2-driver/docs/activity-startup.md"}},{"pageContent":"## How To Test Android App Bundle\n\nGoogle has released the [Android App Bundle](https://developer.android.com/platform/technology/app-bundle/) feature.\nAn `.aab` file is generated by the feature, which we are supposed to upload to the Google Play Store. We can manage the `.aab` file via CLI using the official [bundletool](https://developer.android.com/studio/command-line/bundletool) which is available from [bundletool](https://github.com/google/bundletool). [The guide](https://developer.android.com/guide/app-bundle/) also help us to understand the feature.\n\nWe can get distributed apk files from the `.aab` file via the CLI. Using the generated files, we can test against the release module. Since Appium 1.9.2, you can Appium tests against an `.apks` file using UiAutomator2 driver. [1](https://github.com/appium/appium-adb/pull/367) and [2](https://github.com/appium/appium-base-driver/pull/271) are PRs for the feature.","metadata":{"headerPath":"## How To Test Android App Bundle","sectionCount":1,"filename":"android-appbundle.md","relativePath":"appium-uiautomator2-driver/docs/android-appbundle.md"}},{"pageContent":"## How to run tests\n\n1. Export `bundletool.jar` in your path\n - Appium looks for `bundletool.jar` in your local environemnt. Make sure you can find the path with `which 'bundletool.jar'`. If you can't find it, please set the path correctly.\n - Please make sure the bundletool version is above 1.6.0\n2. Generate the `.apks` file from the `.aab` file\n - The `.aab` is available over Android Studio 3.2\n - You must sign correctly when you generate `.apks` from `.aab`. This step requires data signing.\n\n```bash\n$ java -jar apks/bundletool.jar build-apks \\\n --bundle apks/release/release/app.aab \\ # A generated aab file\n --output apks/AppBundleSample.apks \\ # An apks file you'd like to out put to\n --ks apks/sign \\ # Signing keystore\n --ks-key-alias key0 \\ # Alias of the keytstore\n --ks-pass pass:kazucocoa \\ # Password of the keystore\n --overwrite # Overwrite any existing apks files\n```\n\n3. Use the path to the `.apks` file as your `app` capability.\n\n```ruby\ncapabilities = {\n platformName: :android,\n automationName: 'uiautomator2',\n platformVersion: '8.1',\n deviceName: 'Android Emulator',\n app: \"path/to/your.apks\", # This line is important\n fullReset: true,\n ...\n}\n\ncore = ::Appium::Core.for capabilities: capabilities\ndriver = core.start_driver\n```\n\nYou can find another way to get test APKs in https://developer.android.com/guide/app-bundle/\n\nYou could also install `.apks` bundles via Install App command like below.\n\n```ruby\n# Ruby\ndriver.execute_script 'mobile: installApp', {appPath: 'path/to/your.apks'}\n```\n\n## Tips\n\n## Tips > ### Make `bundletool.jar` executable\n\nMake sure the bundletool is executable.\n`$ chmod 655 /path/to/bundletool.jar` can make it executable, for example.\n\n## Tips > ### Test with different languages\n\nSet `fullReset: true` if you would like to test against the app using different languages' resources.\n\nAppium only installs the minimum set of resources, following the behavior of the appbundle feature. For example, if a device's language is set of English, Appium will only install the `en` resource. The installed apk will have no Japanese resources.\n\nIn orfer to force re-install with a different set of language resources, specify `fullReset: true`\n\n## An example project\n\n- https://github.com/KazuCocoa/AppBundleSample","metadata":{"headerPath":"## How to run tests","sectionCount":5,"filename":"android-appbundle.md","relativePath":"appium-uiautomator2-driver/docs/android-appbundle.md"}},{"pageContent":"## Automating Mobile Gestures With UiAutomator2 Backend\n\nTouch actions are the most advanced and the most complicated way to\nimplement any Android gesture. Although, there is a couple of basic\ngestures, like swipe, fling or pinch, which are commonly used in\nAndroid applications and for which it makes sense to have shortcuts,\nwhere only high-level options are configurable.\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: longClickGesture\n\nThis gesture performs long click action on the given element/coordinates.\nAvailable since Appium v1.19\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: longClickGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be clicked.\n If the element is missing then both click offset coordinates must be provided.\n If both the element id and offset are provided then the coordinates\n are parsed as relative offsets from the top left corner of the element.\n * _x_: The x-offset coordinate\n * _y_: The y-offset coordinate\n * _duration_: Click duration in milliseconds. `500` by default. The value must not be negative\n * _locator_: The map containing [strategy and selector](../README.md#element-location) items to make it possible\n to click dynamic elements.\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: longClickGesture > #### Usage examples\n\n```java\n// Java\n((JavascriptExecutor) driver).executeScript(\"mobile: longClickGesture\", ImmutableMap.of(\n \"elementId\", ((RemoteWebElement) element).getId()\n));\n```\n\n```python\n# Python\ndriver.execute_script('mobile: longClickGesture', {'x': 100, 'y': 100, 'duration': 1000})\n```\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: doubleClickGesture\n\nThis gesture performs double click action on the given element/coordinates.\nAvailable since Appium v1.21\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: doubleClickGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be clicked.\n If the element is missing then both click offset coordinates must be provided.\n If both the element id and offset are provided then the coordinates\n are parsed as relative offsets from the top left corner of the element.\n * _x_: The x-offset coordinate\n * _y_: The y-offset coordinate\n * _locator_: The map containing [strategy and selector](../README.md#element-location) items to make it possible\n to click dynamic elements.","metadata":{"headerPath":"## Automating Mobile Gestures With UiAutomator2 Backend","sectionCount":6,"filename":"android-mobile-gestures.md","relativePath":"appium-uiautomator2-driver/docs/android-mobile-gestures.md"}},{"pageContent":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: doubleClickGesture > #### Usage examples\n\n```java\n// Java\n((JavascriptExecutor) driver).executeScript(\"mobile: doubleClickGesture\", ImmutableMap.of(\n \"elementId\", ((RemoteWebElement) element).getId()\n));\n```\n\n```python\n# Python\ndriver.execute_script('mobile: doubleClickGesture', {'x': 100, 'y': 100})\n```\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: clickGesture\n\nThis gesture performs click action on the given element/coordinates.\nAvailable since Appium UiAutomator2 driver 1.71.0. Usage of this gesture is recommended\nas a possible workaround for cases where the \"native\" tap call fails,\neven though tap coordinates seem correct. This issue is related to the fact\nthese calls use the legacy UIAutomator-based calls while this extension\nis based on the same foundation as W3C does.\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: clickGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be clicked.\n If the element is missing then both click offset coordinates must be provided.\n If both the element id and offset are provided then the coordinates\n are parsed as relative offsets from the top left corner of the element.\n * _x_: The x-offset coordinate\n * _y_: The y-offset coordinate\n * _locator_: The map containing [strategy and selector](../README.md#element-location) items to make it possible\n to click dynamic elements.\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: clickGesture > #### Usage examples\n\n```java\n// Java\ndriver.executeScript(\"mobile: clickGesture\", ImmutableMap.of(\n \"elementId\", ((RemoteWebElement) element).getId()\n));\n```\n\n```python\n# Python\ndriver.execute_script('mobile: clickGesture', {'x': 100, 'y': 100})\n```\n\n```javascript\n// Javascript - @wdio\nawait driver.executeScript('mobile: clickGesture', [{x: 100, y: 100}]);\n```\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: dragGesture\n\nThis gesture performs drag action from the given element/coordinates to the given point.\nAvailable since Appium v1.19","metadata":{"headerPath":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: doubleClickGesture > #### Usage examples","sectionCount":5,"filename":"android-mobile-gestures.md","relativePath":"appium-uiautomator2-driver/docs/android-mobile-gestures.md"}},{"pageContent":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: dragGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be dragged.\n If the element id is missing then both start coordinates must be provided.\n If both the element id and the start coordinates are provided then these\n coordinates are considered as offsets from the top left element corner.\n * _startX_: The x-start coordinate\n * _startY_: The y-start coordinate\n * _endX_: The x-end coordinate. Mandatory argument\n * _endY_: The y-end coordinate. Mandatory argument\n * _speed_: The speed at which to perform this gesture in pixels per second.\n The value must not be negative. The default value is `2500 * displayDensity`\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: dragGesture > #### Usage examples\n\n```java\n// Java\n((JavascriptExecutor) driver).executeScript(\"mobile: dragGesture\", ImmutableMap.of(\n \"elementId\", ((RemoteWebElement) element).getId(),\n \"endX\", 100,\n \"endY\", 100\n));\n```\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: flingGesture\n\nThis gesture performs fling gesture on the given element/area.\nAvailable since Appium v1.19\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: flingGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be flinged.\n If the element id is missing then fling bounding area must be provided.\n If both the element id and the fling bounding area are provided then this\n area is effectively ignored.\n * _left_: The left coordinate of the fling bounding area\n * _top_: The top coordinate of the fling bounding area\n * _width_: The width of the fling bounding area\n * _height_: The height of the fling bounding area\n * _direction_: Direction of the fling. Mandatory value.\n Acceptable values are: `up`, `down`, `left` and `right` (case insensitive)\n * _speed_: The speed at which to perform this\n gesture in pixels per second. The value must be greater than the minimum fling\n velocity for the given view (50 by default). The default value is `7500 * displayDensity`\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: flingGesture > #### Returned value\n\nThe returned value is a boolean one and equals to `true` if the object can still scroll in the given direction","metadata":{"headerPath":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: dragGesture > #### Supported arguments","sectionCount":5,"filename":"android-mobile-gestures.md","relativePath":"appium-uiautomator2-driver/docs/android-mobile-gestures.md"}},{"pageContent":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: flingGesture > #### Usage examples\n\n```java\n// Java\nboolean canScrollMore = (Boolean) ((JavascriptExecutor) driver).executeScript(\"mobile: flingGesture\", ImmutableMap.of(\n \"elementId\", ((RemoteWebElement) element).getId(),\n \"direction\", \"down\",\n \"speed\", 500\n));\n```\n\n```javascript\n// Javascript - @wdio\nawait driver.executeScript('mobile: flingGesture', [{\n elementId: element.elementId,\n direction: 'right',\n speed: 500,\n}]);\n```\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: pinchOpenGesture\n\nThis gesture performs pinch-open gesture on the given element/area.\nAvailable since Appium v1.19\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: pinchOpenGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be pinched.\n If the element id is missing then pinch bounding area must be provided.\n If both the element id and the pinch bounding area are provided then the\n area is effectively ignored.\n * _left_: The left coordinate of the pinch bounding area\n * _top_: The top coordinate of the pinch bounding area\n * _width_: The width of the pinch bounding area\n * _height_: The height of the pinch bounding area\n * _percent_: The size of the pinch as a percentage of the pinch area size.\n Valid values must be float numbers in range 0..1, where 1.0 is 100%.\n Mandatory value.\n * _speed_: The speed at which to perform this gesture in pixels per second.\n The value must not be negative. The default value is `2500 * displayDensity`\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: pinchOpenGesture > #### Usage examples\n\n```java\n// Java\n((JavascriptExecutor) driver).executeScript(\"mobile: pinchOpenGesture\", ImmutableMap.of(\n \"elementId\", ((RemoteWebElement) element).getId(),\n \"percent\", 0.75\n));\n```\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: pinchCloseGesture\n\nThis gesture performs pinch-close gesture on the given element/area.\nAvailable since Appium v1.19","metadata":{"headerPath":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: flingGesture > #### Usage examples","sectionCount":5,"filename":"android-mobile-gestures.md","relativePath":"appium-uiautomator2-driver/docs/android-mobile-gestures.md"}},{"pageContent":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: pinchCloseGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be pinched.\n If the element id is missing then pinch bounding area must be provided.\n If both the element id and the pinch bounding area are provided then the\n area is effectively ignored.\n * _left_: The left coordinate of the pinch bounding area\n * _top_: The top coordinate of the pinch bounding area\n * _width_: The width of the pinch bounding area\n * _height_: The height of the pinch bounding area\n * _percent_: The size of the pinch as a percentage of the pinch area size.\n Valid values must be float numbers in range 0..1, where 1.0 is 100%.\n Mandatory value.\n * _speed_: The speed at which to perform this gesture in pixels per second.\n The value must not be negative. The default value is `2500 * displayDensity`\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: pinchCloseGesture > #### Usage examples\n\n```java\n// Java\n((JavascriptExecutor) driver).executeScript(\"mobile: pinchCloseGesture\", ImmutableMap.of(\n \"elementId\", ((RemoteWebElement) element).getId(),\n \"percent\", 0.75\n));\n```\n\n```python\n# Python\ncan_scroll_more = driver.execute_script('mobile: pinchCloseGesture', {\n 'elementId': element.id,\n 'percent': 0.75\n})\n```\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: swipeGesture\n\nThis gesture performs swipe gesture on the given element/area.\nAvailable since Appium v1.19","metadata":{"headerPath":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: pinchCloseGesture > #### Supported arguments","sectionCount":3,"filename":"android-mobile-gestures.md","relativePath":"appium-uiautomator2-driver/docs/android-mobile-gestures.md"}},{"pageContent":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: swipeGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be swiped.\n If the element id is missing then swipe bounding area must be provided.\n If both the element id and the swipe bounding area are provided then the\n area is effectively ignored.\n * _left_: The left coordinate of the swipe bounding area\n * _top_: The top coordinate of the swipe bounding area\n * _width_: The width of the swipe bounding area\n * _height_: The height of the swipe bounding area\n * _direction_: Swipe direction. Mandatory value.\n Acceptable values are: `up`, `down`, `left` and `right` (case insensitive)\n * _percent_: The size of the swipe as a percentage of the swipe area size.\n Valid values must be float numbers in range 0..1, where 1.0 is 100%.\n Mandatory value.\n * _speed_: The speed at which to perform this gesture in pixels per second.\n The value must not be negative. The default value is `5000 * displayDensity`\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: swipeGesture > #### Usage examples\n\n```java\n// Java\n((JavascriptExecutor) driver).executeScript(\"mobile: swipeGesture\", ImmutableMap.of(\n \"left\", 100, \"top\", 100, \"width\", 200, \"height\", 200,\n \"direction\", \"left\",\n \"percent\", 0.75\n));\n```\n\n```python\n# Python\ndriver.execute_script('mobile: swipeGesture', {\n 'left': 100,\n 'top': 100,\n 'width': 200,\n 'height': 200,\n 'direction': direction, 'percent': 0.75\n})\n```\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: scrollGesture\n\nThis gesture performs scroll gesture on the given element/area.\nAvailable since Appium v1.19","metadata":{"headerPath":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: swipeGesture > #### Supported arguments","sectionCount":3,"filename":"android-mobile-gestures.md","relativePath":"appium-uiautomator2-driver/docs/android-mobile-gestures.md"}},{"pageContent":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: scrollGesture > #### Supported arguments\n\n* _elementId_: The id of the element to be scrolled.\n If the element id is missing then scroll bounding area must be provided.\n If both the element id and the scroll bounding area are provided then this\n area is effectively ignored.\n * _left_: The left coordinate of the scroll bounding area\n * _top_: The top coordinate of the scroll bounding area\n * _width_: The width of the scroll bounding area\n * _height_: The height of the scroll bounding area\n * _direction_: Scrolling direction. Mandatory value.\n Acceptable values are: `up`, `down`, `left` and `right` (case insensitive)\n * _percent_: The size of the scroll as a percentage of the scrolling area size.\n Valid values must be float numbers greater than zero, where 1.0 is 100%.\n Mandatory value.\n * _speed_: The speed at which to perform this gesture in pixels per second.\n The value must not be negative. The default value is `5000 * displayDensity`\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: scrollGesture > #### Returned value\n\nThe returned value is a boolean one and equals to `true` if the object can still scroll in the given direction\n\n## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: scrollGesture > #### Usage examples\n\n```java\n// Java\nboolean canScrollMore = (Boolean) ((JavascriptExecutor) driver).executeScript(\"mobile: scrollGesture\", ImmutableMap.of(\n \"left\", 100, \"top\", 100, \"width\", 200, \"height\", 200,\n \"direction\", \"down\",\n \"percent\", 1.0\n));\n```\n\n```python\n# Python\ncan_scroll_more = driver.execute_script('mobile: scrollGesture', {\n 'left': 100, 'top': 100, 'width': 200, 'height': 200,\n 'direction': 'down',\n 'percent': 3.0\n})\n```","metadata":{"headerPath":"## Automating Mobile Gestures With UiAutomator2 Backend > ### mobile: scrollGesture > #### Supported arguments","sectionCount":3,"filename":"android-mobile-gestures.md","relativePath":"appium-uiautomator2-driver/docs/android-mobile-gestures.md"}},{"pageContent":"# Testing Multi-Window Android Applications\n\nThis guide explains how to test multi-window Android applications using the UiAutomator2 driver, including how windows, displays, and hardware displays relate to each other, and how various settings affect element location and page source generation.\n\n# Testing Multi-Window Android Applications > ## What Are Multi-Window Android Applications?\n\nMulti-window applications are Android applications that can display multiple windows simultaneously on the screen. This includes:\n\n- **Split-screen mode**: Two applications running side-by-side\n- **Picture-in-picture (PiP)**: A video player window floating over other content\n- **Freeform windows**: Desktop-like windowed applications (on supported devices)\n- **System windows**: On-screen keyboards, system dialogs, and notification panels\n- **Overlay windows**: Floating action buttons, tooltips, and other overlay UI elements\n\nEach window in a multi-window environment has its own view hierarchy and can be interacted with independently. The UiAutomator2 driver provides settings and capabilities to handle these complex scenarios.\n\n# Testing Multi-Window Android Applications > ## Windows, Displays, and Hardware Displays\n\nUnderstanding the relationship between these concepts is crucial for effective multi-window testing:\n\n# Testing Multi-Window Android Applications > ## Windows, Displays, and Hardware Displays > ### Windows\n\nA **window** is a container for UI elements that belongs to an application. Each window has:\n- A unique `windowId` identifier\n- A `packageName` identifying the owning application\n- Bounds (`rect`) defining its position and size on screen\n- A Z-order (`layer`) determining which window appears on top\n- A `type` indicating the window type (application, input method, system, etc.)\n- A `title` (may be null)\n- A `physicalDisplayId` (physical display identifier, may be null) - returned as a string\n- A `virtualDisplayId` (virtual display identifier, may be null) - only set for virtual displays\n- State flags: `isActive`, `isFocused`, `isAccessibilityFocused`, `isInPictureInPictureMode`\n\nYou can list all available windows using the [`mobile: listWindows`](../README.md#mobile-listwindows) command, which is essential for understanding the window structure in multi-window scenarios.","metadata":{"headerPath":"# Testing Multi-Window Android Applications","sectionCount":4,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Windows, Displays, and Hardware Displays > ### Displays\n\nA **display** (also called a logical display) is a virtual screen that can contain multiple windows. Each display has:\n- A `displayId` identifier (typically `0` for the default display) - this is the logical display ID\n- A `name` (display name, may be null)\n- A `physicalId` (physical display identifier) that maps to the actual hardware display\n- A `virtualId` (virtual display identifier, may be null) - only set for virtual displays\n- Display metrics (width, height, density, DPI, etc.)\n\nOn Android, the default display (`displayId = 0`) is always present. Additional displays can be created for:\n- External monitors connected via USB-C or HDMI\n- Wireless displays\n- Virtual displays created by applications\n\nYou can list all available displays using the [`mobile: listDisplays`](../README.md#mobile-listdisplays) command to see both logical and physical display identifiers along with their metrics.\n\n# Testing Multi-Window Android Applications > ## Windows, Displays, and Hardware Displays > ### Hardware Displays\n\nA **hardware display** (physical display) is the actual physical screen hardware. Multiple logical displays can map to the same physical display, or a single logical display can span multiple physical displays.\n\n# Testing Multi-Window Android Applications > ## Windows, Displays, and Hardware Displays > ### Multi-Display Support\n\n**Android API 30+ (Android R):**\n- Full multi-display support is available\n- The driver can access windows from all displays using `getWindowsOnAllDisplays()`\n- The `currentDisplayId` setting allows you to target a specific display for element lookup\n- Window operations respect the selected display context\n\n**Before Android API 30:**\n- Only the default display (`displayId = 0`) is accessible\n- `getWindows()` only returns windows from the default display\n- Multi-display operations are not supported\n- The `currentDisplayId` setting has no effect\n\n# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure\n\nThe `mobile: listWindows` command is a powerful tool for understanding and debugging multi-window applications. It returns information about all windows currently available on the device, including their properties and relationships.","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Windows, Displays, and Hardware Displays > ### Displays","sectionCount":4,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Basic Usage\n\n```python\n# List all windows without filters\nwindows = driver.execute_script('mobile: listWindows')\n\n# Print information about each window\nfor window in windows:\n print(f\"Window ID: {window['windowId']}\")\n print(f\"Display ID: {window['displayId']}\")\n print(f\"Physical Display ID: {window['physicalDisplayId']}\")\n if window.get('virtualDisplayId'):\n print(f\"Virtual Display ID: {window['virtualDisplayId']}\")\n print(f\"Package: {window['packageName']}\")\n print(f\"Type: {window['type']}\")\n print(f\"Title: {window['title']}\")\n print(f\"Layer: {window['layer']}\")\n print(f\"Active: {window['isActive']}, Focused: {window['isFocused']}\")\n print(f\"Bounds: {window['rect']}\")\n print(\"---\")\n```\n\n# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Filtering Windows\n\nYou can filter the results to find specific windows:\n\n```python\n# Find windows from a specific package\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'packageName': 'com.example.myapp'\n }\n})\n\n# Find windows on a specific display\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'displayId': 0\n }\n})\n\n# Find windows by physical display ID (note: physicalDisplayId is a string)\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'physicalDisplayId': '1234567890'\n }\n})\n\n# Find a specific window by ID\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'windowId': 42\n }\n})\n\n# Combine multiple filters (AND logic)\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'packageName': 'com.example.myapp',\n 'displayId': 0\n }\n})\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Basic Usage","sectionCount":2,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Advanced Filtering Options\n\nThe `mobile: listWindows` method supports many filter options:\n\n```python\n# Filter by package name with glob patterns\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'packageName': 'com.example.*' # Glob pattern support\n }\n})\n\n# Filter by window type (e.g., TYPE_APPLICATION = 1, TYPE_INPUT_METHOD = 2)\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'type': 1 # Application windows only\n }\n})\n\n# Filter by window title with glob patterns\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'title': 'My App*' # Glob pattern support\n }\n})\n\n# Filter by Z-order layer (higher = on top)\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'layer': 100 # Windows with layer >= 100\n }\n})\n\n# Filter by window state\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'isActive': True,\n 'isFocused': True\n }\n})\n\n# Filter for picture-in-picture windows\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {\n 'isInPictureInPictureMode': True\n }\n})\n```\n\n# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Skipping Screenshots for Performance\n\nBy default, `mobile: listWindows` attempts to take screenshots of each window (on Android API 34+). You can skip this for better performance:\n\n```python\n# Skip screenshots to improve performance\nwindows = driver.execute_script('mobile: listWindows', {\n 'skipScreenshots': True\n})\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Advanced Filtering Options","sectionCount":2,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Practical Use Cases\n\n**1. Debugging Window Visibility Issues:**\n```python\n# Check if your app's window is visible\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {'packageName': 'com.example.myapp'}\n})\nif not windows:\n print(\"App window not found!\")\nelse:\n print(f\"Found {len(windows)} window(s) from the app\")\n```\n\n**2. Finding System Windows (like keyboards):**\n```python\n# Find all system windows\nall_windows = driver.execute_script('mobile: listWindows', {})\nsystem_windows = [w for w in all_windows if w['packageName'] and 'android' in w['packageName']]\nprint(f\"Found {len(system_windows)} system windows\")\n```\n\n**3. Understanding Multi-Display Setup:**\n```python\n# First, list all displays to understand the display structure\ndisplays = driver.execute_script('mobile: listDisplays')\nfor display in displays:\n print(f\"Logical Display ID: {display['id']}\")\n print(f\" Name: {display['name']}\")\n print(f\" Physical ID: {display['physicalId']}\")\n if display.get('virtualId'):\n print(f\" Virtual ID: {display['virtualId']}\")\n print(f\" Is default: {display['isDefault']}\")\n print(f\" Size: {display['metrics']['widthPixels']}x{display['metrics']['heightPixels']}\")\n\n# Group windows by display\nwindows = driver.execute_script('mobile: listWindows', {})\nwindows_by_display = {}\nfor window in windows:\n display_id = window['displayId']\n if display_id not in windows_by_display:\n windows_by_display[display_id] = []\n windows_by_display[display_id].append(window)\n\nprint(f\"Windows on each display: {windows_by_display}\")\n```\n\n**4. Finding Active or Focused Windows:**\n```python\n# Find the currently active window\nactive_windows = driver.execute_script('mobile: listWindows', {\n 'filters': {'isActive': True}\n})\n\n# Find windows with input focus\nfocused_windows = driver.execute_script('mobile: listWindows', {\n 'filters': {'isFocused': True}\n})\n\n# Find the topmost window (highest layer) from your app\napp_windows = driver.execute_script('mobile: listWindows', {\n 'filters': {'packageName': 'com.example.myapp'}\n})\nif app_windows:\n topmost = max(app_windows, key=lambda w: w['layer'])\n print(f\"Topmost window layer: {topmost['layer']}\")\n```\n\n**5. Using Display Information:**\n```python\n# Get display information using mobile: listDisplays\ndisplays = driver.execute_script('mobile: listDisplays')","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Practical Use Cases","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Practical Use Cases\n\n**5. Using Display Information:**\n```python\n# Get display information using mobile: listDisplays\ndisplays = driver.execute_script('mobile: listDisplays')\n\n# Find the default display\ndefault_display = next((d for d in displays if d['isDefault']), None)\nif default_display:\n print(f\"Default display: {default_display['id']}\")\n print(f\" Physical ID: {default_display['physicalId']}\")\n print(f\" Density: {default_display['metrics']['density']}\")\n\n# Use display metrics to calculate coordinates\nfor display in displays:\n metrics = display['metrics']\n center_x = metrics['widthPixels'] / 2\n center_y = metrics['heightPixels'] / 2\n print(f\"Display {display['id']} center: ({center_x}, {center_y})\")\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Using `mobile: listWindows` to Inspect Window Structure > ### Practical Use Cases","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Using `mobile: listDisplays` to Inspect Display Information\n\nThe [`mobile: listDisplays`](../README.md#mobile-listdisplays) command provides information about all displays available on the device, including both logical and physical display identifiers along with detailed metrics.\n\n# Testing Multi-Window Android Applications > ## Using `mobile: listDisplays` to Inspect Display Information > ### Basic Usage\n\n```python\n# List all displays\ndisplays = driver.execute_script('mobile: listDisplays')\n\n# Print information about each display\nfor display in displays:\n print(f\"Logical Display ID: {display['id']}\")\n print(f\" Name: {display['name']}\")\n print(f\" Physical ID: {display['physicalId']}\")\n if display.get('virtualId'):\n print(f\" Virtual ID: {display['virtualId']}\")\n print(f\" Is default: {display['isDefault']}\")\n print(f\" Size: {display['metrics']['widthPixels']}x{display['metrics']['heightPixels']}\")\n print(f\" Density: {display['metrics']['density']} ({display['metrics']['densityDpi']} DPI)\")\n print(\"---\")\n```\n\n# Testing Multi-Window Android Applications > ## Using `mobile: listDisplays` to Inspect Display Information > ### Understanding Display Metrics\n\nEach display includes detailed metrics that can be useful for:\n- Calculating screen coordinates\n- Understanding display density for scaling\n- Determining display capabilities\n\n```python\ndisplays = driver.execute_script('mobile: listDisplays')\nfor display in displays:\n metrics = display['metrics']\n\n # Calculate display center\n center_x = metrics['widthPixels'] / 2\n center_y = metrics['heightPixels'] / 2\n\n # Calculate density-independent pixels (dp)\n dp_width = metrics['widthPixels'] / metrics['density']\n dp_height = metrics['heightPixels'] / metrics['density']\n\n print(f\"Display {display['id']}:\")\n print(f\" Physical pixels: {metrics['widthPixels']}x{metrics['heightPixels']}\")\n print(f\" Density-independent: {dp_width:.1f}x{dp_height:.1f} dp\")\n print(f\" Center: ({center_x}, {center_y})\")\n print(f\" Physical DPI: {metrics['xdpi']:.1f}x{metrics['ydpi']:.1f}\")\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Using `mobile: listDisplays` to Inspect Display Information","sectionCount":3,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Using `mobile: listDisplays` to Inspect Display Information > ### Finding the Default Display\n\n```python\ndisplays = driver.execute_script('mobile: listDisplays')\ndefault_display = next((d for d in displays if d['isDefault']), None)\n\nif default_display:\n print(f\"Default display ID: {default_display['id']}\")\n print(f\"Default display physical ID: {default_display['physicalId']}\")\n```\n\n# Testing Multi-Window Android Applications > ## Using `mobile: listDisplays` to Inspect Display Information > ### Getting Physical Display IDs for Screenshots\n\nThe `physicalId` from `mobile: listDisplays` is the recommended way to get physical display IDs for use with `mobile: screenshots`:\n\n```python\n# Get physical display IDs\ndisplays = driver.execute_script('mobile: listDisplays')\n\n# Take screenshot of each display\nfor display in displays:\n if display.get('physicalId'):\n screenshots = driver.execute_script('mobile: screenshots', {\n 'displayId': display['physicalId']\n })\n print(f\"Screenshot taken for display {display['id']} (physical: {display['physicalId']})\")\n```\n\n# Testing Multi-Window Android Applications > ## Element Location Strategy in Multi-Window Applications\n\nThe UiAutomator2 driver uses different strategies for locating elements depending on the locator type and settings configuration.\n\n# Testing Multi-Window Android Applications > ## Element Location Strategy in Multi-Window Applications > ### UiObject2-Based Locators (Recommended)\n\nUiObject2-based locators support multi-window scenarios and are affected by the following settings:\n\n- **`id`** (resource ID)\n- **`accessibility id`** (content description)\n- **`className`**\n- **`xpath`** (when used with proper window context)\n\nThese locators work with the window selection logic controlled by `enableMultiWindows`, `currentDisplayId` and `enableTopmostWindowFromActivePackage` settings.","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Using `mobile: listDisplays` to Inspect Display Information > ### Finding the Default Display","sectionCount":4,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Element Location Strategy in Multi-Window Applications > ### Legacy UiObject-Based Selectors (Limited Support)\n\nThe **`-android uiautomator`** strategy uses the legacy `UiSelector` API, which:\n- **Does not support multi-window lookups**\n- Only searches within the active window\n- Cannot access elements in other windows even when `enableMultiWindows` is enabled\n- Should be avoided for multi-window scenarios\n\nIf you need to use UiSelector-based locators, consider using the newer UiObject2-based alternatives instead.\n\n# Testing Multi-Window Android Applications > ## Settings That Affect Element Location","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Element Location Strategy in Multi-Window Applications > ### Legacy UiObject-Based Selectors (Limited Support)","sectionCount":2,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Settings That Affect Element Location > ### `currentDisplayId`\n\n**Type:** `integer`\n**Default:** `0` (default display)\n**Available since:** Android API 30+\n\nThe `currentDisplayId` setting determines which display is used for element lookup operations when using UiObject2-based locators.\n\n**How it works:**\n- When set to a specific display ID, all element lookups are scoped to that display\n- Only windows from the specified display are considered during element search\n- This setting is applied to `BySelector` objects via the `displayId()` method\n- If the specified display ID doesn't exist, an error is thrown\n- Set to `-1` to reset the setting to its default behavior (use the default display)\n\n**Example:**\n```python\n# Set the current display to display 1\ndriver.update_settings({'currentDisplayId': 1})\n\n# Now all element lookups will search only on display 1\nelement = driver.find_element('id', 'myButton')\n\n# Reset to default display behavior\ndriver.update_settings({'currentDisplayId': -1})\n```\n\n**Note:** This setting only affects UiObject2-based locators (`id`, `accessibility id`, `className`). It has no effect on legacy `-android uiautomator` selectors or xpath lookups (which use their own window selection logic).\n\n**Screenshot Behavior:**\n- When `currentDisplayId` is set to a custom value, the standard `getScreenshot()` method will take a screenshot of the specified display\n\n**Coordinate-Based Gesture Behavior:**\n- Coordinate-based gestures (taps, swipes, drags, etc. performed using x/y coordinates) are executed on either the default active display or the display specified by `currentDisplayId`\n- When `currentDisplayId` is set, all coordinate-based gestures will target that display\n- This includes gestures performed via:\n - W3C Actions API (pointer actions with coordinates)\n - Mobile gesture commands (`mobile: clickGesture`, `mobile: swipeGesture`, etc.) when coordinates are provided\n - Direct coordinate-based interactions\n- This ensures that gestures are performed on the correct display in multi-display scenarios\n\n**Example:**\n```python\n# Set display 1 as current\ndriver.update_settings({'currentDisplayId': 1})\n\n# Coordinate-based gestures will now target display 1\ndriver.execute_script('mobile: clickGesture', {'x': 100, 'y': 200})\n\n# Reset to default display\ndriver.update_settings({'currentDisplayId': 0})\n\n# Gestures will now target the default display\ndriver.execute_script('mobile: clickGesture', {'x': 100, 'y': 200})\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Settings That Affect Element Location > ### `currentDisplayId`","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Settings That Affect Element Location > ### `enableMultiWindows`\n\n**Type:** `boolean`\n**Default:** `false`\n\nThe `enableMultiWindows` setting controls whether multiple windows are included in the accessibility tree used for element location and page source generation.\n\n**When `false` (default):**\n- Only the active window's root node is retrieved\n- Element lookups search only within the active window\n- Page source contains only the active window's hierarchy\n- This is the fastest and most common configuration\n\n**When `true`:**\n- All accessible windows are retrieved and included in the accessibility tree\n- Element lookups can find elements across all windows\n- Page source includes content from all windows\n- Useful when you need to interact with system windows (like keyboards) or overlay windows\n\n**Example:**\n```python\n# Enable multi-window mode\ndriver.update_settings({'enableMultiWindows': True})\n\n# Now you can find elements in the on-screen keyboard or other windows\nkeyboard_key = driver.find_element('id', 'keyboard_key_a')\n```\n\n**Important considerations:**\n- Enabling this setting may impact performance as more windows need to be processed\n- The window selection logic also depends on `enableTopmostWindowFromActivePackage`\n- This setting affects both element location and page source generation","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Settings That Affect Element Location > ### `enableMultiWindows`","sectionCount":1,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Settings That Affect Element Location > ### `enableTopmostWindowFromActivePackage`\n\n**Type:** `boolean`\n**Default:** `false`\n\nThe `enableTopmostWindowFromActivePackage` setting determines which window from the active application package is used when `enableMultiWindows` is `false`.\n\n**When `false` (default):**\n- Uses `getRootInActiveWindow()` to get the active window root\n- This is the window that currently has focus\n- May not be the topmost window if the app has multiple windows\n\n**When `true`:**\n- Searches all windows from the active package\n- Selects the window with the highest Z-order (topmost layer)\n- Useful when an app has multiple windows and you want to interact with the one on top\n\n**Example:**\n```python\n# Enable topmost window selection\ndriver.update_settings({'enableTopmostWindowFromActivePackage': True})\n\n# Now element lookups will use the topmost window from your app\nelement = driver.find_element('id', 'myButton')\n```\n\n**Interaction with `enableMultiWindows`:**\n- When `enableMultiWindows` is `true`, this setting is ignored (all windows are included)\n- When `enableMultiWindows` is `false` and this setting is `true`, only the topmost window from the active package is used\n- When both are `false`, the active window is used\n\n# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation\n\nThe page source (XML hierarchy) generation is directly affected by the window selection settings. **Note:** XPath lookups use the same page source, so the rules described here apply to both page source generation and XPath queries.\n\nThe interaction between `enableMultiWindows` and `currentDisplayId` determines which windows are included:\n\n# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### When `enableMultiWindows` is `true` and `currentDisplayId` is set\n\n- Only windows belonging to the specified display are included in the page source\n- Each window's hierarchy from that display is merged into the XML tree\n- Fastest multi-window configuration since it's limited to one display\n- Elements from windows on other displays are not visible in the page source","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Settings That Affect Element Location > ### `enableTopmostWindowFromActivePackage`","sectionCount":3,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### When `enableMultiWindows` is `true` and `currentDisplayId` is not customized\n\n- All accessible windows from all displays are included in the page source\n- Each window's hierarchy is merged into the XML tree\n- You can see elements from:\n - The main application window\n - On-screen keyboard\n - System dialogs\n - Overlay windows\n - Other application windows (in split-screen mode)\n - Windows from all connected displays\n\n# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### When `enableMultiWindows` is `false` and `currentDisplayId` is set\n\n- Only the active window's hierarchy is included\n- `currentDisplayId` is effectively ignored in this case, as only the active window is used regardless of which display it's on\n- Fastest generation time\n- Smallest XML output\n- Elements from other windows are not visible in the page source\n\n# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### When `enableMultiWindows` is `false` and `currentDisplayId` is not customized\n\n- Only the active window's hierarchy is included (or topmost window if `enableTopmostWindowFromActivePackage: true`)\n- Fastest generation time\n- Smallest XML output\n- Elements from other windows are not visible in the page source","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### When `enableMultiWindows` is `true` and `currentDisplayId` is not customized","sectionCount":3,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### XPath Lookups\n\nXPath lookups use the same window selection logic as page source generation. The interaction between `enableMultiWindows` and `currentDisplayId` determines which windows are included:\n\n- **When `enableMultiWindows` is `true` and `currentDisplayId` is set**: The page source only includes windows belonging to the specified display. Xpath can find elements across all windows from that display.\n- **When `enableMultiWindows` is `true` and `currentDisplayId` is not customized**: The page source includes windows from all displays. Xpath can find elements across all windows from all displays.\n- **When `enableMultiWindows` is `false` and `currentDisplayId` is set**: The page source only includes the active window. `currentDisplayId` is effectively ignored in this case, as only the active window is used regardless of which display it's on.\n- **When `enableMultiWindows` is `false` and `currentDisplayId` is not customized**: The page source only includes the active window (or topmost window if `enableTopmostWindowFromActivePackage` is `true`). Xpath searches only within that single window.\n\n**Using `window-id` Attribute to Fine-Tune XPath Lookups:**\n\nWhen `enableMultiWindows` is enabled and `currentDisplayId` is not customized, elements from multiple windows are included in the page source. Each element has a `window-id` attribute that identifies which window it belongs to. You can use this attribute in your xpath queries to target elements from specific windows.\n\n**Important:** Using `window-id` in xpath only makes sense when:\n- `enableMultiWindows` is `true` (multiple windows are included in the page source)\n- `currentDisplayId` is not customized (not set to a specific display)\n\n**Why?**\n- When `enableMultiWindows` is `false`, only one window is included in the page source, so all elements have the same `window-id`\n- When `currentDisplayId` is set to a specific display, only windows from that display are included, so all elements would have the same `window-id` (or windows from the same display)\n- Only when multiple windows from potentially different displays are included does the `window-id` attribute provide meaningful differentiation\n\n**Example:**\n```python\n# Enable multi-windows for xpath searches (without setting currentDisplayId)\ndriver.update_settings({'enableMultiWindows': True})","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### XPath Lookups","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### XPath Lookups\n\n**Example:**\n```python\n# Enable multi-windows for xpath searches (without setting currentDisplayId)\ndriver.update_settings({'enableMultiWindows': True})\n\n# First, find the window ID you want to target\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {'packageName': 'com.example.myapp'}\n})\ntarget_window_id = windows[0]['windowId']\n\n# Use window-id attribute in xpath to target a specific window\nelement = driver.find_element('xpath', f'//*[@window-id=\"{target_window_id}\" and @text=\"My Button\"]')\n\n# Or find all elements in a specific window\nelements = driver.find_elements('xpath', f'//*[@window-id=\"{target_window_id}\"]')\n```\n\n**Note:** The `window-id` attribute is only available when the element's window identifier can be determined. In rare cases, this attribute might not be present for some elements.","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## How Settings Affect Page Source Generation > ### XPath Lookups","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Best Practices\n\n1. **Use UiObject2-based locators** (`id`, `accessibility id`, `className`) instead of legacy `-android uiautomator` selectors for multi-window scenarios\n\n2. **Start with default settings** and only enable `enableMultiWindows` when you specifically need to interact with multiple windows\n\n3. **Use `currentDisplayId`** when testing on devices with multiple displays (Android API 30+)\n\n4. **Enable `enableTopmostWindowFromActivePackage`** when your app has multiple windows, and you want to interact with the visible one\n\n5. **Reset accessibility cache** using [`mobile: resetAccessibilityCache`](../README.md#mobile-resetaccessibilitycache) if you encounter stale element references after window changes\n\n6. **List windows** using [`mobile: listWindows`](../README.md#mobile-listwindows) to understand the window structure before writing locators. Use filtering to find specific windows and verify which windows are accessible for element location.\n\n# Testing Multi-Window Android Applications > ## Example: Testing a Split-Screen Application\n\n```python\nfrom appium import webdriver\nfrom appium.options.android import UiAutomator2Options\n\n# Setup\noptions = UiAutomator2Options()\noptions.app_package = 'com.example.myapp'\ndriver = webdriver.Remote('http://localhost:4723', options=options)\n\n# Enable multi-window support\ndriver.update_settings({\n 'enableMultiWindows': True\n})\n\n# List all windows to see what's available\nwindows = driver.execute_script('mobile: listWindows', {})\nprint(f\"Found {len(windows)} windows\")\n\n# Filter to find windows from your app\napp_windows = driver.execute_script('mobile: listWindows', {\n 'filters': {'packageName': 'com.example.myapp'}\n})\nprint(f\"Found {len(app_windows)} windows from the app\")\n\n# Find elements - now searches across all windows\nelement = driver.find_element('id', 'myButton')\n\n# Get page source - includes all windows\nsource = driver.get_page_source()\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Best Practices","sectionCount":2,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Example: Testing on Multiple Displays\n\n```python\ndisplays = driver.execute_script('mobile: listDisplays')\n\n# Set the current display for element lookups\ndriver.update_settings({'currentDisplayId': displays[1]['id']})\n\n# All subsequent element lookups will search on the second display\nelement = driver.find_element('id', 'myButton')\n\n# Screenshots will also be taken from the second display\nscreenshot = driver.get_screenshot_as_base64()\n\n# Reset to default display (using -1)\ndriver.update_settings({'currentDisplayId': -1})\n```\n\n# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support\n\nScreenshots are an important part of multi-window and multi-display testing. The UiAutomator2 driver provides two methods for taking screenshots that work with multiple displays.\n\n# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### How `currentDisplayId` Affects Screenshots\n\nWhen the `currentDisplayId` setting is configured to a non-default display:\n\n- **Standard screenshots** (`getScreenshot()`, `get_screenshot_as_base64()`, etc.) will capture the specified display\n- The driver automatically detects if the display has custom density or is a non-default display\n- For better compatibility with custom displays, the driver may use the `screencap` command instead of the standard screenshot API\n- If the device under test is an emulator and has a virtual display, then it is only possible to take the virtual\n display screenshot since Android API 34 or newer.\n- This ensures that screenshots match the display context you're currently testing\n\n**Example:**\n```python\n# Set display 1 as current\ndriver.update_settings({'currentDisplayId': 1})\n\n# This screenshot will be from display 1\nscreenshot = driver.get_screenshot_as_base64()\n\n# Reset to default display (using -1)\ndriver.update_settings({'currentDisplayId': -1})\n\n# Now screenshots will be from the default display\nscreenshot = driver.get_screenshot_as_base64()\n```\n\n# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots\n\nThe [`mobile: screenshots`](../README.md#mobile-screenshots) method provides more control over multi-display screenshot capture. This method is available since Android 10 (API 29).","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Example: Testing on Multiple Displays","sectionCount":4,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Taking Screenshots of All Displays\n\n```python\n# Get screenshots of all available displays\nscreenshots = driver.execute_script('mobile: screenshots', {})\n\n# screenshots is a dictionary where keys are display IDs\nfor display_id, display_info in screenshots.items():\n print(f\"Display {display_id}: {display_info['name']}\")\n print(f\" Is default: {display_info['isDefault']}\")\n print(f\" Screenshot size: {len(display_info['payload'])} bytes\")\n # display_info['payload'] contains base64-encoded PNG data\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Taking Screenshots of All Displays","sectionCount":1,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Taking Screenshots of a Specific Display\n\n**Recommended approach:** Use `mobile: listDisplays` to get physical or virtual display IDs:\n\n```python\n# Get display ID from mobile: listDisplays (recommended)\ndisplays = driver.execute_script('mobile: listDisplays')\n\n# For physical displays, use physicalId\nif displays and displays[0].get('physicalId') is not None:\n display_id = displays[0]['physicalId']\n\n # Use the physical display ID to take a screenshot\n screenshots = driver.execute_script('mobile: screenshots', {\n 'displayId': display_id\n })\n\n # Returns a dictionary with one entry\n display_info = screenshots[display_id]\n screenshot_data = display_info['payload'] # base64-encoded PNG\n\n# For virtual displays, use virtualId\nelif displays and displays[0].get('virtualId') is not None:\n display_id = displays[0]['virtualId']\n\n # Use the virtual display ID to take a screenshot\n screenshots = driver.execute_script('mobile: screenshots', {\n 'displayId': display_id\n })\n\n # Returns a dictionary with one entry\n display_info = screenshots[display_id]\n screenshot_data = display_info['payload'] # base64-encoded PNG\nelse:\n print(\"Display ID not available\")\n```\n\n**Alternative approach:** Get display ID from `mobile: listWindows`:\n\n```python\n# Get display ID from a window\nwindows = driver.execute_script('mobile: listWindows', {\n 'filters': {'packageName': 'com.example.myapp'}\n})\n\nif windows:\n window = windows[0]\n display_id = None\n\n # Prefer physical display ID, fall back to virtual if available\n if window.get('physicalDisplayId') is not None:\n display_id = window['physicalDisplayId']\n elif window.get('virtualDisplayId') is not None:\n display_id = window['virtualDisplayId']\n\n if display_id:\n # Use the display ID to take a screenshot\n screenshots = driver.execute_script('mobile: screenshots', {\n 'displayId': display_id\n })\n\n # Returns a dictionary with one entry\n display_info = screenshots[display_id]\n screenshot_data = display_info['payload'] # base64-encoded PNG\n else:\n print(\"Display ID not available for this window\")\n```\n\n**Direct usage:** You can also use a known physical or virtual display ID directly:\n\n```python\n# Get screenshot of a specific physical display ID\nscreenshots = driver.execute_script('mobile: screenshots', {\n 'displayId': '1234567890' # Physical display ID (string)\n})","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Taking Screenshots of a Specific Display","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Taking Screenshots of a Specific Display\n\n```python\n# Get screenshot of a specific physical display ID\nscreenshots = driver.execute_script('mobile: screenshots', {\n 'displayId': '1234567890' # Physical display ID (string)\n})\n\n# Or use a virtual display ID\nscreenshots = driver.execute_script('mobile: screenshots', {\n 'displayId': '12345' # Virtual display ID (string)\n})\n\n# Returns a dictionary with one entry\ndisplay_info = screenshots['1234567890'] # or '12345' for virtual\nscreenshot_data = display_info['payload'] # base64-encoded PNG\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Taking Screenshots of a Specific Display","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Understanding Display Identifiers\n\n**Important:** The display identifiers used by `mobile: screenshots` are **physical or virtual display IDs**, which are different from the logical display IDs used by `currentDisplayId` setting.\n\n- **Logical display ID** (`currentDisplayId`): Used for element location, window operations, and standard screenshots. Typically starts at 0. You can get this from the `id` field returned by `mobile: listDisplays`.\n- **Physical display ID** (`mobile: screenshots`): Used for the `mobile: screenshots` method with physical displays. Returned as a string to avoid JavaScript number precision issues. You can get this value from:\n - The `physicalId` field returned by `mobile: listDisplays` (recommended)\n - The `physicalDisplayId` field returned by `mobile: listWindows` (note: this is a string)\n - The `adb shell dumpsys SurfaceFlinger --display-id` command output\n- **Virtual display ID** (`mobile: screenshots`): Used for the `mobile: screenshots` method with virtual displays. Returned as a string. You can get this value from:\n - The `virtualId` field returned by `mobile: listDisplays` (recommended)\n - The `virtualDisplayId` field returned by `mobile: listWindows` (note: this is a string)\n - The `adb shell dumpsys SurfaceFlinger --display-id` command output\n\n**Example workflow:**\n```python\n# 1. List displays to see all available displays with their IDs\ndisplays = driver.execute_script('mobile: listDisplays')\nfor display in displays:\n print(f\"Logical Display ID: {display['id']}\")\n print(f\" Physical ID: {display['physicalId']}\")\n if display.get('virtualId'):\n print(f\" Virtual ID: {display['virtualId']}\")\n print(f\" Is default: {display['isDefault']}\")\n print(f\" Size: {display['metrics']['widthPixels']}x{display['metrics']['heightPixels']}\")\n\n# 2. List windows to see which windows are on which displays\nwindows = driver.execute_script('mobile: listWindows', {})\nfor window in windows:\n print(f\"Window ID: {window['windowId']}\")\n print(f\" Logical display ID: {window['displayId']}\")\n print(f\" Physical display ID: {window['physicalDisplayId']}\") # Note: string type\n if window.get('virtualDisplayId'):\n print(f\" Virtual display ID: {window['virtualDisplayId']}\")\n print(f\" Package: {window['packageName']}\")\n print(f\" Type: {window['type']}, Layer: {window['layer']}\")","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Understanding Display Identifiers","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Understanding Display Identifiers\n\n# 3. Use currentDisplayId for element operations (logical display)\ndriver.update_settings({'currentDisplayId': 0}) # Or use -1 to reset to default\nelement = driver.find_element('id', 'myButton')\n\n# 4. Use mobile: screenshots with physical or virtual display IDs\n# Get display ID from mobile: listDisplays (recommended)\ndefault_display = next((d for d in displays if d['isDefault']), None)\nif default_display:\n # Prefer physical ID, fall back to virtual ID if available\n display_id = default_display.get('physicalId') or default_display.get('virtualId')\n if display_id:\n screenshots = driver.execute_script('mobile: screenshots', {\n 'displayId': display_id\n })\n display_info = screenshots[display_id]\n screenshot_data = display_info['payload']\n```\n\n**Example:**\n```python\nscreenshots = driver.execute_script('mobile: screenshots', {})\n\nfor display_id, info in screenshots.items():\n print(f\"Display ID: {display_id}\")\n print(f\" Name: {info['name']}\")\n print(f\" Default: {info['isDefault']}\")\n print(f\" Screenshot: {info['payload'][:50]}...\") # First 50 chars\n```","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Using `mobile: screenshots` for Multi-Display Screenshots > #### Understanding Display Identifiers","sectionCount":1,"recursiveSplit":true,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Best Practices for Screenshots in Multi-Display Scenarios\n\n1. **Use `currentDisplayId` for standard screenshots** when you want screenshots to match your current testing context\n2. **Use `mobile: screenshots`** when you need screenshots from multiple displays simultaneously or want to target specific physical or virtual displays\n3. **Be aware of the difference** between logical display IDs (`currentDisplayId`) and physical/virtual display IDs (`mobile: screenshots`)\n4. **Use `mobile: listDisplays`** to get display IDs - This is the recommended way to obtain physical or virtual display IDs along with display metrics. The `physicalId` field (for physical displays) or `virtualId` field (for virtual displays), both returned as strings, can be used directly with `mobile: screenshots`\n5. **Use `mobile: listWindows`** to understand which windows are on which displays - The `physicalDisplayId` field (for physical displays) or `virtualDisplayId` field (for virtual displays), both returned as strings, can also be used with `mobile: screenshots` if you need to screenshot the display containing a specific window\n6. **Alternative: Use `adb shell dumpsys SurfaceFlinger --display-id`** if you need to find all display IDs without using the driver methods\n\n# Testing Multi-Window Android Applications > ## References\n\n- [Android Multi-Window Support](https://developer.android.com/guide/topics/large-screens/multi-window-support)\n- [AccessibilityWindowInfo API](https://developer.android.com/reference/android/view/accessibility/AccessibilityWindowInfo)\n- [UiAutomator2 Server Source Code](https://github.com/appium/appium-uiautomator2-server)","metadata":{"headerPath":"# Testing Multi-Window Android Applications > ## Screenshots and Multi-Display Support > ### Best Practices for Screenshots in Multi-Display Scenarios","sectionCount":2,"filename":"android-multiwindow.md","relativePath":"appium-uiautomator2-driver/docs/android-multiwindow.md"}},{"pageContent":"# Supported BiDi Commands And Events\n\nOnly events and commands mentioned below are supported.\nAll other entities described in the spec throw not implemented errors.\n\n# Supported Events\n\n# Supported Events > ## log.entryAdded\n\nThis event is emitted if the driver retrieves a new entry for any of the below log types.\n\n# Supported Events > ## log.entryAdded > ### syslog\n\nEvents are emitted for both emulator and real devices. Each event contains a single device logcat line.\nEvents are always emitted with the `NATIVE_APP` context.\nThese events might be disabled if the `appium:skipLogcatCapture` capability is enabled.\n\n# Supported Events > ## log.entryAdded > ### server\n\nEvents are emitted for both emulator and real devices. Each event contains a single Appium server log line.\nEvents are always emitted with the `NATIVE_APP` context.\nEvents are only emitted if the `get_server_logs` server security feature is enabled.\n\n# Supported Events > ## appium:uiautomator2.contextUpdate\n\nThis event is emitted upon the context change, either explicit or implicit.\nThe event is always emitted upon new session initialization.\nSee the [GitHub feature ticket](https://github.com/appium/appium/issues/20741) for more details.\n\n# Supported Events > ## appium:uiautomator2.contextUpdate > ### CDDL\n\n```cddl\nappium:uiautomator2.contextUpdated = {\n method: \"appium:uiautomator2.contextUpdated\",\n params: {\n name: text,\n type: \"NATIVE\" / \"WEB\",\n },\n}\n```\n\nThe event contains the following params:\n\n# Supported Events > ## appium:uiautomator2.contextUpdate > ### name\n\nContains the actual name of the new context, for example `NATIVE_APP`.\n\n# Supported Events > ## appium:uiautomator2.contextUpdate > ### type\n\nEither `NATIVE` or `WEB` depending on which context is currently active in the driver session.","metadata":{"headerPath":"# Supported BiDi Commands And Events","sectionCount":9,"filename":"bidi.md","relativePath":"appium-uiautomator2-driver/docs/bidi.md"}},{"pageContent":"## Basic Examples of Session Capability Sets\n\nThis article describes necessary capabilities that must be provided in order\nto implement some common automation testing scenarios.\nIt only describes very minimum sets of capabilities required to\nbe included. For refined setups more of them might need to be provided. Check the\n[Capabilities](../README.md#capabilities) section in README for more details\non each option available for the fine-tuning of UIAutomator2 driver sessions.\n\n## Basic Examples of Session Capability Sets > ### Application File (Real Device)\n\n```json\n{\n \"platformName\": \"Android\",\n \"appium:automationName\": \"uiautomator2\",\n \"appium:platformVersion\": \"<Android_Version>\",\n \"appium:udid\": \"<Phone_ID>\",\n \"appium:app\": \"/path/to/local/package.apk\"\n}\n```\n\n`appium:app` could also be a remote app or an archive:\n\n```\n \"appium:app\": \"https://example.com/package.apk\"\n \"appium:app\": \"https://example.com/package.zip\"\n```\n\nSometimes it might also be necessary to explicitly provide\n`appium:appPackage` and `appium:appActivity` capability values\nif the driver is unable to autodetect them from the provided app package manifest.\nCheck the [How To Troubleshoot Activities Startup](./activity-startup.md) article\nfor more details.\n\n## Basic Examples of Session Capability Sets > ### Application File (Emulator)\n\n```json\n{\n \"platformName\": \"Android\",\n \"appium:automationName\": \"uiautomator2\",\n \"appium:avd\": \"<Emulator_Name>\",\n \"appium:platformVersion\": \"<Android_Version>\",\n \"appium:app\": \"/path/to/local/package.apk\"\n}\n```\n\n`appium:app` could also be a remote app or an archive:\n\n```\n \"appium:app\": \"https://example.com/package.apk\"\n```\n\n## Basic Examples of Session Capability Sets > ### Chrome (Real Device)\n\n```json\n{\n \"platformName\": \"Android\",\n \"appium:automationName\": \"uiautomator2\",\n \"browserName\": \"Chrome\",\n \"appium:platformVersion\": \"<Android_Version>\",\n \"appium:udid\": \"<Phone_ID>\"\n}\n```\n\n## Basic Examples of Session Capability Sets > ### Chrome (Emulator)\n\n```json\n{\n \"platformName\": \"Android\",\n \"appium:automationName\": \"uiautomator2\",\n \"browserName\": \"Chrome\",\n \"appium:avd\": \"<Emulator_Name>\",\n \"appium:platformVersion\": \"<Android_Version>\"\n}\n```","metadata":{"headerPath":"## Basic Examples of Session Capability Sets","sectionCount":5,"filename":"capability-sets.md","relativePath":"appium-uiautomator2-driver/docs/capability-sets.md"}},{"pageContent":"## Basic Examples of Session Capability Sets > ### Pre-Installed App (Real Device)\n\n```json\n{\n \"platformName\": \"Android\",\n \"appium:automationName\": \"uiautomator2\",\n \"appium:platformVersion\": \"<Android_Version>\",\n \"appium:udid\": \"<Phone_ID>\",\n \"appium:appPackage\": \"<App_Package_Id>\",\n \"appium:appActivity\": \"<App_Activity_Id>\",\n \"appium:noReset\": true\n}\n```\n\nThe `appium:noReset` capability is set to `true` in order to tell the driver\nthe app identified by `appium:appPackage` is already preinstalled and must not be reset.\n\n## Basic Examples of Session Capability Sets > ### Pre-Installed App (Emulator)\n\n```json\n{\n \"platformName\": \"Android\",\n \"appium:automationName\": \"uiautomator2\",\n \"appium:avd\": \"<Emulator_Name>\",\n \"appium:platformVersion\": \"<Android_Version>\",\n \"appium:appPackage\": \"<App_Package_Id>\",\n \"appium:appActivity\": \"<App_Activity_Id>\",\n \"appium:noReset\": true\n}\n```\n\n## Basic Examples of Session Capability Sets > ### Custom Launch (Real Device)\n\n```json\n{\n \"platformName\": \"Android\",\n \"appium:automationName\": \"uiautomator2\",\n \"appium:platformVersion\": \"<Android_Version>\",\n \"appium:udid\": \"<Phone_ID>\"\n}\n```\n\nThis will start your test at the Home screen.\nAfterwards you may use any of the application management\nmethods, like [mobile: installApp](../README.md#mobile-installapp)\nor [mobile: activateApp](../README.md#mobile-activateapp)\nto manage the life cycle of your app or switch between contexts to\nmanage web pages. Check the full list of\n[mobile: execute methods](../README.md#platform-specific-extensions) for more details.\n\n## Basic Examples of Session Capability Sets > ### Custom Launch (Emulator)\n\n```json\n{\n \"platformName\": \"Android\",\n \"appium:automationName\": \"uiautomator2\",\n \"appium:avd\": \"<Emulator_Name>\",\n \"appium:platformVersion\": \"<Android_Version>\"\n}\n```","metadata":{"headerPath":"## Basic Examples of Session Capability Sets > ### Pre-Installed App (Real Device)","sectionCount":4,"filename":"capability-sets.md","relativePath":"appium-uiautomator2-driver/docs/capability-sets.md"}},{"pageContent":"# Scheduled Actions\n\n# Scheduled Actions > ## Problem Statement\n\nSometimes it is necessary to verify a UI scenario where one has to assert a UI control has appeared on the screen and then perform a decision action on this control. An example of such control might be a notification or any other popup that automatically disappears shortly after being shown. The WebDriver protocol uses HTTP REST API to communicate with clients. This means if you want to assert the existence of the above popup in your test script or perform any action on it then it is necessary to send an HTTP request to the server and receive an answer from it. Furthermore, this is needed for each particular command or assertion you want to perform, e.g. click, find element, get text, etc. The time an HTTP request needs to reach the server and then its response to reach the client is the roundtrip time, and the length of it depends on many factors. For some complex setups the roundtrip duration may even be counted in seconds, which makes it impossible to quickly handle an UI element, because it would already not exist/disappear by the time your next request reaches the server.\n\n# Scheduled Actions > ## Scheduled Actions Concept\n\nIn order to address the problem above we have created the Scheduled Actions concept. The main idea there is to run the action code on the server side in asynchronous manner and only retrieve the detailed execution history if needed. `Action` is this context means emulating a gesture, or taking a screenshot, or taking a xml page source. More actions could be added later. The `scheduled` means after you create an action, or rather describe it in JSON, it is parsed and stored by the server for the further async execution. The client does not have any control over the previously scheduled action and can only unschedule it later or fetch its execution history. All actions are being scheduled on the main UI thread. All scheduled actions are reset automatically upon a new session creation.\n\nThis feature is available in the UIA2 driver since version *2.26.0*\n\n# Scheduled Actions > ## mobile: scheduleAction\n\nAdds a new action to the list of scheduled actions.","metadata":{"headerPath":"# Scheduled Actions","sectionCount":4,"filename":"scheduled-actions.md","relativePath":"appium-uiautomator2-driver/docs/scheduled-actions.md"}},{"pageContent":"# Scheduled Actions > ## mobile: scheduleAction > ### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nname | string | yes | The unique name of the action. | popupHandlingAction\nsteps | ActionStep[] | yes | One or more action steps to execute. Steps are executed in sequential order. All steps are executed even if any of them fails. The execution is considered failed if at least one step fails. | Check [Action Steps](#action-steps)\nmaxPass | number | no | If set to a number greater than zero then the action will stop rescheduling itself after it passes the desired number of times | 1\nmaxFail | number | no | If set to a number greater than zero then the action will stop rescheduling itself after it fails the desired number of times | 1\ntimes | number | no | How many times the action must be executed itself. 1 by default | 10\nintervalMs | number | no | How long the interval in milliseconds between the next action reschedule should be. 1000 ms by default. | 100\nmaxHistoryItems | number | no | The maximum size of the history items array that are stored for this action. Each action execution creates a new history item. All items are sorted in descending order by action execution timestamp. If the amount of executions reaches `maxHistoryItems` value then the oldest history item gets deleted. Be careful to not set this parameter to large values as you might get out of memory issues. 20 history items are being stored for each action by default. | 100\n\n# Scheduled Actions > ## mobile: scheduleAction > ### Arguments > #### Action Steps\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntype | string | yes | One of supported step types: `gesture`, `source`, `screenshot`. | gesture\nname | string | yes | Step name. It must not be unique, but is useful to track the step execution history. | click\npayload | map | yes | Step payload. The payload format depends on the actual step type. | Check on [Step Payload](#step-payload) below","metadata":{"headerPath":"# Scheduled Actions > ## mobile: scheduleAction > ### Arguments","sectionCount":2,"filename":"scheduled-actions.md","relativePath":"appium-uiautomator2-driver/docs/scheduled-actions.md"}},{"pageContent":"# Scheduled Actions > ## mobile: scheduleAction > ### Arguments > #### Step Payload\n\nEach step payload is required to contain the `subtype` item. Then the combination of step's `type` and `subtype` defines the actual payload content:\n\nType | Subtype | Description | Payload Example\n--- | --- | --- | ---\ngesture | click | The payload is expected to be similar to the one the [mobile: clickGesture](./android-mobile-gestures.md#mobile-clickgesture) requires. | {subtype: 'click', locator: {strategy: 'id', selector: 'buttonIdentifier'}}\ngesture | longClick | The payload is expected to be similar to the one the [mobile: longClickGesture](./android-mobile-gestures.md#mobile-longclickgesture) requires. | {subtype: 'click', locator: {strategy: 'accessbility id', selector: 'buttonIdentifier'}}\ngesture | doubleClick | The payload is expected to be similar to the one the [mobile: doubleClickGesture](./android-mobile-gestures.md#mobile-doubleclickgesture) requires. | {subtype: 'click', elementId: 'yolo', x: 150, y: 200}\nsource | xml | The payload does not need to contain any other items. | {subtype: 'xml'}\nscreenshot | png | The payload does not need to contain any other items. | {subtype: 'png'}\n\n# Scheduled Actions > ## mobile: getActionHistory\n\nReturns the history of executions for the particular action.\n\n# Scheduled Actions > ## mobile: getActionHistory > ### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nname | string | yes | The unique name of the action. | popupHandlingAction","metadata":{"headerPath":"# Scheduled Actions > ## mobile: scheduleAction > ### Arguments > #### Step Payload","sectionCount":3,"filename":"scheduled-actions.md","relativePath":"appium-uiautomator2-driver/docs/scheduled-actions.md"}},{"pageContent":"# Scheduled Actions > ## mobile: getActionHistory > ### Returned Result\n\nThe history of executions of the particular action. An error is thrown if no action with the given name has been scheduled before calling this API or if it has been already unscheduled.\n\nThe returned result map has the following items:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nrepeats | number | The number of times this action has been repeated so far. | 1\nstepResults | list&lt;list&lt;map&gt;&gt; | The history of step executions for each action run. Items in this list are sorted by execution timestamp in descending order. The maximum length of the list is limited by `maxHistoryItems` action value | See below\n\nThe result of each action step is represented by the map inside each `stepResulsts` array item containing the following items:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nname | string | The name of the corresponding step. | clickStep\ntype | string | One of supported step typed. | gesture\ntimestamp | number | The Unix timestamp in milliseconds when the step started its execution. | 1685370112000\npassed | boolean | Whether the step has passed, e.g. no exceptions occurred during its execution. | true\nresult | any | The actual step result. Depends on the step type and subtype. Might be null. Always null if exception is not null. | something\nexception | map | If an exception happens during the step execution then this map will contain the following items: name (the exception class name), message (the actual exception message), stacktrace (full exception stacktrace). If no exceptions occurs during step execution then the value of this item is always null | {name: 'java.lang.Exception', message: 'Bad things happen', stacktrace: 'happened somewhere'}\n\n# Scheduled Actions > ## mobile: unscheduleAction\n\nUnschedules an action from the async execution and returns its history.\n\n# Scheduled Actions > ## mobile: unscheduleAction > ### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nname | string | yes | The unique name of the action. | popupHandlingAction\n\n# Scheduled Actions > ## mobile: unscheduleAction > ### Returned Result\n\nThe same as in [mobile: getActionHistory](#mobile-getactionhistory) endpoint","metadata":{"headerPath":"# Scheduled Actions > ## mobile: getActionHistory > ### Returned Result","sectionCount":4,"filename":"scheduled-actions.md","relativePath":"appium-uiautomator2-driver/docs/scheduled-actions.md"}},{"pageContent":"# Scheduled Actions > ## Usage Example\n\nLet's assume our application under test shows a short-living popup with two buttons to either accept or reject it.\nAt first, we need to figure out how the popup looks like in the page source to build element locators. For that we are going to create an action that periodically retrieves page source snapshots:\n\n```python\ndriver.execute_script('mobile: scheduleAction', {\n 'name': 'myPopupHandlingAction',\n 'steps': [{\n 'type': 'source',\n 'name': 'fetchPageSourceStep',\n 'payload': {\n 'subtype': 'xml'\n }\n }],\n 'intervalMs': 1000,\n 'times': 30,\n 'maxHistoryItems': 30,\n})\n\n# doing some other stuff which is supposed to trigger the popup for the next 30 seconds\n\nhistory: Dict[str, Any] = driver.execute_script('mobile: unscheduleAction', {\n 'name': 'myPopupHandlingAction',\n})\n```\n\nIn the example above we have scheduled an action which takes UI hierarchy snapshot every second. Eventually we can\ndebug the value of `history` list and inspect each item for the presence of our expected popup element. After we have figured out locators for its Accept button our action may be updated to:\n\n```python\ndriver.execute_script('mobile: scheduleAction', {\n 'name': 'myPopupHandlingAction',\n 'steps': [{\n 'type': 'gesture',\n 'name': 'acceptPopupStep',\n 'payload': {\n 'subtype': 'click'\n 'locator': {\n 'strategy': 'id',\n 'selector': 'acceptButtonIdentifier',\n }\n }\n }],\n 'intervalMs': 1000,\n 'times': 30,\n 'maxPass': 1,\n 'maxHistoryItems': 30,\n})\n\n# doing some other stuff which is supposed to trigger the popup for the next 30 seconds\n\nhistory: Dict[str, Any] = driver.execute_script('mobile: unscheduleAction', {\n 'name': 'myPopupHandlingAction',\n})\n\ndef did_execution_pass(execution: List[Dict]) -> bool:\n return all((step['passed'] for step in execution))\n\nassert any((did_execution_pass(execution) for exection in history['stepResults']))\n```","metadata":{"headerPath":"# Scheduled Actions > ## Usage Example","sectionCount":1,"filename":"scheduled-actions.md","relativePath":"appium-uiautomator2-driver/docs/scheduled-actions.md"}},{"pageContent":"## Guide on UiAutomator Locator Types\n\nUIA2 driver enables elements lookup using [UiSelector](https://developer.android.com/reference/androidx/test/uiautomator/UiSelector).\n[UiScrollable](https://developer.android.com/reference/androidx/test/uiautomator/UiScrollable)\nis also supported.\nBoth locator types are supported natively by Google's [UiAutomator](https://developer.android.com/training/testing/other-components/ui-automator) framework for Android. With these locators you could create flexible ways to reference complicated element paths, and their performance is very close to native.\n\n## Guide on UiAutomator Locator Types > ### Examples\n\nNote that the index selector is unreliable so prefer instance instead. The\nfollowing examples are written against the [ApiDemos](https://github.com/appium/android-apidemos) apk using Ruby.\n\nFind the first textview.\n\n```ruby\n# ruby\nfirst_textview = find_element(:uiautomator, 'new UiSelector().className(\"android.widget.TextView\").instance(0)');\n```\n\nFind the first element by text.\n\n```ruby\n# ruby\nfirst_text = find_element(:uiautomator, 'new UiSelector().text(\"Animation\")')\nfirst_text.text # \"Animation\"\n```\n\nFind the first scrollable element, then find a TextView with the text \"Tabs\".\nThe \"Tabs\" element will be scrolled into view.\n\n```ruby\n# ruby\nelement = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className(\"android.widget.TextView\"), \"Tabs\")')\n```\n\nAs a special case, scrollIntoView returns the element that is scrolled into view.\nscrollIntoView allows scrolling to any UiSelector.\n\n```ruby\n# ruby\nelement = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text(\"WebView\").instance(0));')\nelement.text # \"WebView\"\n```","metadata":{"headerPath":"## Guide on UiAutomator Locator Types","sectionCount":2,"filename":"uiautomator-uiselector.md","relativePath":"appium-uiautomator2-driver/docs/uiautomator-uiselector.md"}},{"pageContent":"## Guide on UiAutomator Locator Types > ### More Resources\n\n- [How to Use UISelector in Appium](http://code2test.com/appium-tutorial/how-to-use-uiselector-in-appium/)\n- [How to use UiSelector to inspect elements on Android](https://www.automationtestinghub.com/uiselector-android/)\n- [UiAutomatorParserTests.java](https://github.com/appium/appium-uiautomator2-server/blob/master/app/src/test/java/io/appium/uiautomator2/utils/UiAutomatorParserTests.java)\n- [UiScrollableParserTests.java](https://github.com/appium/appium-uiautomator2-server/blob/master/app/src/test/java/io/appium/uiautomator2/utils/UiScrollableParserTests.java)\n- [UiSelectorParserTests.java](https://github.com/appium/appium-uiautomator2-server/blob/master/app/src/test/java/io/appium/uiautomator2/utils/UiSelectorParserTests.java)","metadata":{"headerPath":"## Guide on UiAutomator Locator Types > ### More Resources","sectionCount":1,"filename":"uiautomator-uiselector.md","relativePath":"appium-uiautomator2-driver/docs/uiautomator-uiselector.md"}},{"pageContent":"# Unlock\n\nUiAutomator2 driver allows dealing with the Android lock screen using various APIs.\nThis article describes available APIs and their options.\n\n# Unlock > ## Unlock On Session Startup\n\nUiAutomator2 provides the following [capabilities](../../README.md#device-locking) to deal\nwith the system lock screen:\n\n- appium:unlockStrategy\n- appium:unlockSuccessTimeout\n- appium:skipUnlock\n- appium:unlockType\n- appium:unlockKey\n\nThese capabilities could be used to unlock the device under test during the driver session initialization\nas well as deal with different lock screen types.\n\n# Unlock > ## Unlock On Session Startup > ### appium:unlockStrategy\n\nEither `locksettings` (default since Android 8/API level 26) or `uiautomator` (legacy).\n\nThe `locksettings` strategy uses `adb shell locksettings` CLI to deal with different\ntypes of device lock screens. It is fast, reliable, but has one downside: the actual\npin, pattern or password must be temporarily removed in order to unlock the device and restored afterwards.\n\nSetting the strategy to `uiautomator` will enforce the driver to use UiAutomator framework in order\nto interact with the device's lock screen for various unlock types. It might be slower and less stable in comparison\nto the `locksettings` strategy, although there is no other alternative if tests are being executed on an older Android version\nor the application under test requires the device to constantly maintain display lock settings.\n\n# Unlock > ## Unlock On Session Startup > ### appium:unlockSuccessTimeout\n\nMaximum number of milliseconds to wait until the device is unlocked. `2000` ms by default\n\n# Unlock > ## Unlock On Session Startup > ### appium:skipUnlock\n\nThe `appium:skipUnlock` capability is enabled by default and makes the driver to detect and handle the lock screen\nupon session startup _if it is present_. If the lock screen cannot be detected upon session startup then nothing will be\ndone. By default, it is assumed the device has a \"simple\" lock screen, which could be removed by waking up the device.\nIn case the device has a different type of the lock screen configured in its settings then the information about it\nmust be provided in the below capability values.\n\n# Unlock > ## Unlock On Session Startup > ### appium:unlockType and appium:unlockKey\n\nThis capability supports the following possible values:","metadata":{"headerPath":"# Unlock","sectionCount":6,"filename":"main.md","relativePath":"appium-uiautomator2-driver/docs/unlock/main.md"}},{"pageContent":"# Unlock > ## Unlock On Session Startup > ### appium:unlockType and appium:unlockKey > #### pin\n\nAssumes the device is protected with a PIN code. Expects the `appium:unlockKey` to contain a valid pin consisting\nof digits in range 0-9, for example `1111`.\n\n# Unlock > ## Unlock On Session Startup > ### appium:unlockType and appium:unlockKey > #### pinWithKeyEvent\n\nSame as [pin](#pin), but uses ADB instead of UiAutomator framework to enter the actual pin value.\n\n# Unlock > ## Unlock On Session Startup > ### appium:unlockType and appium:unlockKey > #### password\n\nAssumes the device is protected with a password. Expects the `appium:unlockKey` to contain a valid password consisting\nof latin characters, for example `abcd1234`.\n\n# Unlock > ## Unlock On Session Startup > ### appium:unlockType and appium:unlockKey > #### pattern\n\nAssumes the device is protected with a secret pattern. Check the example below for more details on the `appium:unlockKey`\nvalue for this particular unlock type.\n\n# Unlock > ## Unlock On Session Startup > ### appium:unlockType and appium:unlockKey > #### pattern > ##### Example\n\nLet say you have a device that is locked with a pattern similar to the one on the image below,\nand you want to run a test over that device.\n\n<img src=\"./screen1.png\" />\n\nWe treat the pattern pins similarly to numbers on a digital phone dial. So, in this case the *unlockKey* is `729854163`\n\n<img src=\"./screen2.png\" />\n\nand capabilities are:\n\n```json\n{\n \"appium:unlockType\": \"pattern\",\n \"appium:unlockKey\": \"729854163\"\n}\n```\n\n# Unlock > ## Mid-Session Unlock\n\nThere is also a possibility to interact with the device's lock screen while the test session is running.\nUse the following mobile extensions for this purpose:\n\n- [mobile: lock](../../README.md#mobile-lock)\n- [mobile: unlock](../../README.md#mobile-unlock)\n- [mobile: isLocked](../../README.md#mobile-islocked)","metadata":{"headerPath":"# Unlock > ## Unlock On Session Startup > ### appium:unlockType and appium:unlockKey > #### pin","sectionCount":6,"filename":"main.md","relativePath":"appium-uiautomator2-driver/docs/unlock/main.md"}},{"pageContent":"# appium-xcuitest-driver\n\n[![npm version](http://img.shields.io/npm/v/appium-xcuitest-driver.svg)](https://npmjs.org/package/appium-xcuitest-driver)\n[![Downloads](http://img.shields.io/npm/dm/appium-xcuitest-driver.svg)](https://npmjs.org/package/appium-xcuitest-driver)\n\n[![Release](https://github.com/appium/appium-xcuitest-driver/actions/workflows/publish.js.yml/badge.svg)](https://github.com/appium/appium-xcuitest-driver/actions/workflows/publish.js.yml)\n\nThis is an [Appium](https://appium.github.io/appium) driver for automating iOS applications on iOS,\niPadOS, and tvOS.\n\n> [!IMPORTANT]\n> Only macOS is supported as the host platform, as it requires Xcode and developer tools.\n\n> [!IMPORTANT]\n> Since major version *10.0.0*, this driver is only compatible with Appium 3. Use the `appium driver install xcuitest`\n> command to add it to your distribution.\n\n# appium-xcuitest-driver > ## Documentation\n\nThe [Documentation](https://appium.github.io/appium-xcuitest-driver) is hosted separately at\n[https://appium.github.io/appium-xcuitest-driver](https://appium.github.io/appium-xcuitest-driver)\n\n# appium-xcuitest-driver > ## Contributing & Development\n\nClone this project from GitHub and run:\n\n```bash\nnpm install\n```\n\nTo watch changes during the development:\n\n```bash\nnpm run watch\n```\n\nTo run unit/functional tests:\n\n```bash\nnpm test # unit\nnpm run e2e-test # functional\n```\n\nThere are also a number of environment variables that can be used when running\nthe tests locally. These include:\n\n* `REAL_DEVICE` - set to anything truthy, makes the tests use real device capabilities\n* `_FORCE_LOGS` - set to `1` to get the log output, not just spec\n* `PLATFORM_VERSION` - change the version to run the tests against (defaults to `9.3`)\n* `XCCONFIG_FILE` - specify where the xcode config file is for a real device run (if\n blank, and running a real device test, it will search for the first file in\n the root directory of the repo with the extension \"xcconfig\")\n* `UICATALOG_REAL_DEVICE` - path to the real device build of UICatalog, in case\n the npm installed one is not built for real device","metadata":{"headerPath":"# appium-xcuitest-driver","sectionCount":3,"filename":"README.md","relativePath":"appium-xcuitest-driver/README.md"}},{"pageContent":"---\nhide:\n - navigation\n - toc\n\ntitle: Contributing\n---\n\nContributions to this project are welcome! To start off, clone it from GitHub and run:\n\n```bash\nnpm install\n```\n\nTo watch changes during development:\n\n```bash\nnpm run watch\n```\n\nTo run unit/functional tests:\n\n```bash\nnpm run test # unit \nnpm run e2e-test # functional\n```\n\nTo develop documentation:\n\n```bash\nnpm run install-docs-deps # install the dependencies (Python packages)\nnpm run dev:docs # serve the docs locally and watch for changes\n```\n\nThere are also a number of environment variables that can be used when running\nthe tests locally. These include:\n\n* `REAL_DEVICE` - set to anything truthy, makes the tests use real device capabilities\n* `_FORCE_LOGS` - set to `1` to get the log output, not just spec\n* `PLATFORM_VERSION` - change the version to run the tests against (defaults to `11.3`)\n* `XCCONFIG_FILE` - specify where the Xcode config file is for a real device run (if\n blank, and running a real device test, it will search for the first file in\n the root directory of the repo with the extension `.xcconfig`)\n* `UICATALOG_REAL_DEVICE` - path to the real device build of UICatalog, in case\n the `npm` installed one is not built for a real device","metadata":{"headerPath":"","sectionCount":1,"filename":"contributing.md","relativePath":"appium-xcuitest-driver/docs/contributing.md"}},{"pageContent":"## WebDriverAgent JSONWP Endpoints\n\n## WebDriverAgent JSONWP Endpoints > ### Session-less commands\n\n| method | endpoint | req params | opt params |\n| ------ | -------------------------------------- | ---------- | ---------- |\n| POST | /wda/homescreen | | |\n| GET | /source | | accessible |\n| GET | /inspector | | |\n| GET | /inspector.js | | |\n| GET | /screenshot | | |\n| POST | /session | desiredCapabilities\n| GET | /status | | |\n| GET | /* | ** | |\n| POST | /* | ** | |\n| PUT | /* | ** | |\n| DELETE | /* | ** | |","metadata":{"headerPath":"## WebDriverAgent JSONWP Endpoints","sectionCount":2,"filename":"endpoints-wda.md","relativePath":"appium-xcuitest-driver/docs/endpoints-wda.md"}},{"pageContent":"## WebDriverAgent JSONWP Endpoints > ### Session commands\n\n| method | endpoint | req params | opt params |\n| ------ | -------------------------------------- | ---------- | ---------- |\n| GET | /alert/text | | |\n| POST | /alert/accept | | |\n| POST | /alert/dismiss | | |\n| POST | /wda/deactivateApp | | duration |\n| POST | /timeouts | * | |\n| GET | /source | | accessible |\n| GET | /element/:uuid/enabled | | |\n| GET | /element/:uuid/rect | | |\n| GET | /element/:uuid/attribute/:name | | |\n| GET | /element/:uuid/text | | |\n| GET | /element/:uuid/displayed | | |\n| GET | /wda/element/:uuid/accessible | | |\n| GET | /element/:uuid/name | | |\n| POST | /element/:uuid/value | value | |\n| POST | /element/:uuid/click | | |\n| POST | /element/:uuid/clear | | |\n| POST | /wda/element/:uuid/doubleTap | | |\n| POST | /wda/element/:uuid/touchAndHold | duration | |\n| POST | /wda/element/:uuid/scroll | | name, direction, predicateString, toVisible |\n| POST | /uiaElement/:uuid/value | value | |\n| POST | /wda/element/:uuid/dragfromtoforduration | fromX, fromY, toX, toY, duration | |\n| POST | /wda/tap/:uuid | x, y | |\n| POST | /wda/keys | value | |\n| GET | /window/size | | |\n| POST | /element | using, value | |\n| POST | /elements | using, value | |\n| GET | /wda/uiaElement/:uuid/getVisibleCells | | |\n| POST | /element/:uuid/element | using, value | |\n| POST | /element/:uuid/elements | using, value | |\n| GET | /orientation | | |\n| POST | /orientation | orientation | |\n| GET | /screenshot | | |\n| POST | /wda/touch_id | match | |\n\n\n\\* implemented but intentionally not supported\n\n** not implemented handlers","metadata":{"headerPath":"## WebDriverAgent JSONWP Endpoints > ### Session commands","sectionCount":1,"filename":"endpoints-wda.md","relativePath":"appium-xcuitest-driver/docs/endpoints-wda.md"}},{"pageContent":"## Appium iOS JSONWP Endpoints\n\n## Appium iOS JSONWP Endpoints > ### Session-less commands\n\n| method | endpoint | req params | opt params |\n| ------ | ---------------------------------------- | ---------- | ---------- |\n| GET | /status | | |\n| POST | /session | desiredCapabilities | requiredCapabilities |\n| GET | /sessions | | |","metadata":{"headerPath":"## Appium iOS JSONWP Endpoints","sectionCount":2,"filename":"endpoints.md","relativePath":"appium-xcuitest-driver/docs/endpoints.md"}},{"pageContent":"## Appium iOS JSONWP Endpoints > ### Session commands\n\n| method | endpoint | req params | opt params |\n| ------ | ---------------------------------------- | ---------- | ---------- |\n| GET | /:sessionId | | |\n| DELETE | /:sessionId | | |\n| POST | /timeouts | type, ms | |\n| POST | /timeouts/async_script | ms | |\n| POST | /timeouts/implicit_wait | ms | |\n| GET | /window_handle | | |\n| GET | /window_handles | | |\n| GET | /url | | |\n| POST | /url | url | |\n| POST | /forward | none | |\n| POST | /back | none | |\n| POST | /refresh | none | |\n| POST | /execute | script, args | |\n| POST | /execute_async | script, args | |\n| GET | /screenshot | | |\n| POST | /frame | id | |\n| POST | /window | name | |\n| DELETE | /window | | |\n| GET | /window/:windowhandle/size | | |\n| GET | /cookie | | |\n| POST | /cookie | cookie | |\n| DELETE | /cookie | | | | |\n| DELETE | /cookie/:name | | |\n| GET | /source | | |\n| GET | /title | | |\n| POST | /element | using, value | |\n| POST | /elements | using, value | |\n| POST | /element/active | none | |\n| POST | /element/:elementId/element | using, value | |\n| POST | /element/:elementId/elements | using, value | |\n| POST | /element/:elementId/click | none | |\n| POST | /element/:elementId/submit | none | |\n| GET | /element/:elementId/text | none | |\n| POST | /element/:elementId/value | value | |\n| POST | /keys | value | |\n| GET | /element/:elementId/name | | |\n| POST | /element/:elementId/clear | none | |","metadata":{"headerPath":"## Appium iOS JSONWP Endpoints > ### Session commands","sectionCount":1,"recursiveSplit":true,"filename":"endpoints.md","relativePath":"appium-xcuitest-driver/docs/endpoints.md"}},{"pageContent":"## Appium iOS JSONWP Endpoints > ### Session commands\n\n| POST | /keys | value | |\n| GET | /element/:elementId/name | | |\n| POST | /element/:elementId/clear | none | |\n| GET | /element/:elementId/selected | | |\n| GET | /element/:elementId/enabled | | |\n| GET | /element/:elementId/attribute/:name | | |\n| GET | /element/:elementId/equals/:otherId | | |\n| GET | /element/:elementId/displayed | | |\n| GET | /element/:elementId/location | | |\n| GET | /element/:elementId/location_in_view | | |\n| GET | /element/:elementId/size | | |\n| GET | /element/:elementId/css/:propertyName | | |\n| GET | /orientation | | |\n| POST | /orientation | orientation | |\n| GET | /alert_text | | |\n| POST | /alert_text | text | |\n| POST | /accept_alert | none | |\n| POST | /dismiss_alert | none | |\n| POST | /click | | button |\n| GET | /location | | |\n| POST | /location | location | |\n| POST | /log | type | |\n| GET | /log/types | | |\n| GET | /context | | |\n| POST | /context | name | |\n| GET | /contexts | | |\n| POST | /receive_async_response | status, value | |","metadata":{"headerPath":"## Appium iOS JSONWP Endpoints > ### Session commands","sectionCount":1,"recursiveSplit":true,"filename":"endpoints.md","relativePath":"appium-xcuitest-driver/docs/endpoints.md"}},{"pageContent":"## Appium iOS JSONWP Endpoints > ### Appium-specific commands\n\n| method | endpoint | req params | opt params |\n| ------ | ---------------------------------------- | ---------- | ---------- |\n| POST | /appium/device/shake | none | |\n| GET | /appium/device/system_time | | |\n| POST | /appium/device/lock | | seconds |\n| POST | /appium/device/rotate | x, y, radius, rotation, touchCount, duration | element |\n| POST | /appium/device/remove_app | appId or bundleId | |\n| POST | /appium/device/hide_keyboard | | strategy, key, keyCode, keyName |\n| POST | /appium/device/push_file | path, data | |\n| POST | /appium/device/pull_file | path | |\n| POST | /appium/device/pull_folder | path | |\n| POST | /appium/simulator/touch_id | match | |\n| POST | /appium/app/launch | none | |\n| POST | /appium/app/close | none | |\n| POST | /appium/app/background | seconds | |\n| POST | /appium/app/strings | | language, stringFile |\n| POST | /appium/element/:elementId/value | value | |\n| POST | /appium/receive_async_response | response | |","metadata":{"headerPath":"## Appium iOS JSONWP Endpoints > ### Appium-specific commands","sectionCount":1,"filename":"endpoints.md","relativePath":"appium-xcuitest-driver/docs/endpoints.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Attach to a Running WebDriverAgent\n---\n\nThe XCUITest driver provides the __`appium:webDriverAgentUrl`__ capability to attach to a running\nWebDriverAgent (WDA) application. This works for real devices and simulators, but the primary usage\nis for real devices.\n\n## Usage\n\n1. Start a WebDriverAgent application on a device\n2. Start an XCUITest driver session with `appium:webDriverAgentUrl` capability\n\nPlease read [Manage WebDriverAgent by Yourself](./wda-custom-server.md) and\n[Real Device Configuration](../preparation/real-device-config.md) about how to prepare WDA for a\nreal device.\n\nThe `appium:webDriverAgentUrl` value should be the WDA URL: `http://<reachable ip address for the device>:8100`.\nIf the environment has port-forward to the connected device, it can be `http://localhost:8100`.\n\n```json\n{\n \"platformName\": \"ios\",\n \"appium:automationName\": \"xcuitest\",\n \"appium:platformVersion\": \"15.5\",\n \"appium:udid\": \"<device udid>\",\n \"appium:deviceName\": \"iPhone\",\n \"appium:webDriverAgentUrl\": \"http://<reachable ip address for the device>:8100\"\n}\n```\n\nThis method allows you to manage the WDA process by yourself. The XCUITest driver then simply\nattaches to the WDA process, which may improve the application performance.\n\nSome XCUITest driver APIs (for example,\n[mobile: calibrateWebToRealCoordinatesTranslation](../reference/execute-methods.md#mobile-calibratewebtorealcoordinatestranslation))\nmight still require the port number of the remote device if it is a real device. Providing the\n`appium:webDriverAgentUrl` capability might not be sufficient to recognize the remote port number,\nin case it is different from the local one. Consider settings the `appium:wdaRemotePort` capability\nin such cases, to supply the driver with the appropriate data.","metadata":{"headerPath":"","sectionCount":2,"filename":"attach-to-running-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/attach-to-running-wda.md"}},{"pageContent":"---\ntitle: Audio Capture\n---\n\n\nAppium XCUITest driver provides a possibility to record iOS audio stream and save it to a file,\nwhich could be then retrieved on the client side. Apple does not provide any API to directly\nretrieve the audio stream from a Simulator or a real device, but it is possible to redirect that\nstream to the host machine, where it could be captured.\n\n* [`mobile: startAudioRecording`](../reference/execute-methods.md#mobile-startaudiorecording)\n* [`mobile: stopAudioRecording`](../reference//execute-methods.md#mobile-stopaudiorecording)\n\n## Server Requirements\n\n- The host machine must have [`ffmpeg`](https://www.ffmpeg.org/download.html) installed and added to PATH.\n It can be installed via [`brew`](https://brew.sh/): `brew install ffmpeg`.\n- For macOS 10.15+, applications recording Microphone audio need to be explicitly granted this permission.\n This can be done in the following settings menu:\n\n - macOS < 13: _System Preferences -> Security & Privacy -> Privacy -> Microphone_\n - macOS 13+: _System Settings -> Privacy & Security -> Microphone_\n\n Ensure that either `ffmpeg` itself or the parent Appium process (e.g. Terminal) is present in that list.\n\n- As this is a potentially insecure feature, it must be explicitly allowed on the server side. See\n [the Appium documentation on Security](https://appium.io/docs/en/latest/guides/security/) for more details.\n The feature name is `audio_record`.\n\n## Simulator Setup\n\nThe following steps are necessary to setup iOS Simulator audio capture:\n\n* Install [Soundflower](https://github.com/mattingalls/Soundflower/releases)\n* Redirect Simulator audio output to Soundflower: from the main Simulator menu, select\n _I/O -> Audio Output -> Soundflower (2ch)_\n* In terminal, run `ffmpeg -f avfoundation -list_devices true -i \"\"` to get the identifier of the\n `Soundflower (2ch)` device. This identifier prefixed with `:` will be then used as `audioInput`\n argument to `mobile: startAudioRecording` call\n* Test that your setup works as expected. Run any audio playback in Simulator and execute the\n following command in Terminal, replacing the `-i` argument value with the one you got from the\n previous step:\n ```\n ffmpeg -t 5 -f avfoundation -i \":1\" -c:a aac -b:a 128k -ac 2 -ar 44100 -y ~/Desktop/out.mp4\n ```\n After 5 seconds, a file named `out.mp4` should be created on your desktop, containing the recorded\n audio stream.","metadata":{"headerPath":"","sectionCount":3,"filename":"audio-capture.md","relativePath":"appium-xcuitest-driver/docs/guides/audio-capture.md"}},{"pageContent":"## Real Device Setup\n\nThe following steps are necessary to setup iOS Real Device audio capture:\n\n* Connect your device to the Mac host with a cable\n* Open the _Audio MIDI Setup_ application\n * Via Finder: _Applications -> Utilities -> Audio MIDI Setup_\n * Via terminal: `open -a /System/Applications/Utilities/Audio\\ MIDI\\ Setup.app`\n* Find your phone in the list of devices there and click `Enable` next to it\n* In terminal, run `ffmpeg -f avfoundation -list_devices true -i \"\"` to get the identifier of your\n device in the `AVFoundation audio devices` list. This identifier prefixed with `:` will be then\n used as `audioInput` argument to `mobile: startAudioRecording` call\n* Test that your setup works as expected. Run any audio playback on the device and execute the\n following command in Terminal, replacing the `-i` argument value with the value you got from the\n previous step:\n ```\n ffmpeg -t 5 -f avfoundation -i \":1\" -c:a aac -b:a 128k -ac 2 -ar 44100 -y ~/Desktop/out.mp4\n ```\n After 5 seconds, a file named `out.mp4` should be created on your desktop, containing the recorded\n audio stream.\n\n!!! note\n\n Apple does not allow phone calls to be redirected this way. You can only record application or system sounds.\n\n## Further Reading\n\n* <https://github.com/appium/appium-xcuitest-driver/pull/1207>\n* <https://www.macobserver.com/tips/quick-tip/iphone-audio-input-mac/>\n* <http://www.lorisware.com/blog/2012/04/28/recording-iphone-emulator-video-with-sound/>","metadata":{"headerPath":"## Real Device Setup","sectionCount":2,"filename":"audio-capture.md","relativePath":"appium-xcuitest-driver/docs/guides/audio-capture.md"}},{"pageContent":"---\ntitle: Basic Examples of Session Capability Sets\n---\n\nThis article describes necessary capabilities that must be provided in order\nto implement some common automation testing scenarios.\nIt only describes very minimum sets of capabilities required to\nbe included. For refined setups more of them might need to be provided. Check the\n[Capabilities](../reference/capabilities.md) article for more details\non each option available for the fine-tuning of XCUITest driver sessions.\n\n### Application File (Real Device)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"appium:platformVersion\": \"<iOS_Version>\",\n \"appium:udid\": \"<Phone_UUID>\",\n \"appium:app\": \"/path/to/local/package.ipa\"\n}\n```\n\n`appium:app` could also be a remote app or an archive:\n\n```\n \"appium:app\": \"https://example.com/package.ipa\"\n \"appium:app\": \"https://example.com/package.zip\"\n```\n\n`appium:udid` could also be set to `auto` in order to select the first matched device\nconnected to the host (or a single one if only one is connected):\n\n```\n \"appium:udid\": \"auto\"\n```\n\n### Application File (Simulator)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"appium:deviceName\": \"<Simulator_Name>\",\n \"appium:platformVersion\": \"<iOS_Version>\",\n \"appium:app\": \"/path/to/local/package.app\"\n}\n```\n\n`appium:app` could also be an archive:\n\n```\n \"appium:app\": \"https://example.com/package.zip\"\n \"appium:app\": \"/path/to/local/package.zip\"\n```\n\n### Safari (Real Device)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"browserName\": \"Safari\",\n \"appium:platformVersion\": \"<iOS_Version>\",\n \"appium:udid\": \"<Phone_UUID>\"\n}\n```\n\nYou may also provide `appium:safariInitialUrl` capability value to navigate\nto the desired page during the session startup:\n\n```\n \"appium:safariInitialUrl\": \"https://server.com/page\"\n```\n\n### Safari (Simulator)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"browserName\": \"Safari\",\n \"appium:deviceName\": \"<Simulator_Name>\",\n \"appium:platformVersion\": \"<iOS_Version>\"\n}\n```","metadata":{"headerPath":"","sectionCount":5,"filename":"capability-sets.md","relativePath":"appium-xcuitest-driver/docs/guides/capability-sets.md"}},{"pageContent":"### Pre-Installed App (Real Device)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"appium:platformVersion\": \"<iOS_Version>\",\n \"appium:udid\": \"<Phone_UUID>\",\n \"appium:bundleId\": \"<Bundle_ID_Of_Preinstalled_App>\",\n \"appium:noReset\": true\n}\n```\n\nThe `appium:noReset` capability is set to `true` in order to tell the driver\nthe app identified by `appium:bundleId` is already preinstalled and must not be reset.\n\n### Pre-Installed App (Simulator)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"appium:deviceName\": \"<Simulator_Name>\",\n \"appium:platformVersion\": \"<iOS_Version>\",\n \"appium:bundleId\": \"<Bundle_ID_Of_Preinstalled_App>\",\n \"appium:noReset\": true\n}\n```\n\n### Deeplink (Real Device running iOS 17+)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"appium:platformVersion\": \"<iOS_Version>\",\n \"appium:udid\": \"<Phone_UUID>\",\n \"appium:initialDeeplinkUrl\": \"<Deeplink_Url>\"\n}\n```\n\n### Deeplink (Simulator running iOS 17+)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"appium:deviceName\": \"<Simulator_Name>\",\n \"appium:platformVersion\": \"<iOS_Version>\",\n \"appium:initialDeeplinkUrl\": \"<Deeplink_Url>\"\n}\n```\n\n### Custom Launch (Real Device)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"appium:platformVersion\": \"<iOS_Version>\",\n \"appium:udid\": \"<Phone_UUID>\",\n}\n```\n\nThis will start your test at the Home screen.\nAfterwards you may use any of the application management\nmethods, like [mobile: installApp](../reference//execute-methods.md#mobile-installapp)\nor [mobile: activateApp](../reference//execute-methods.md#mobile-activateapp)\nto manage the life cycle of your app or switch between contexts to\nmanage web pages. Check the full list of\n[mobile: execute methods](../reference/execute-methods.md) for more details.\n\n### Custom Launch (Simulator)\n\n```json\n{\n \"platformName\": \"iOS\",\n \"appium:automationName\": \"XCUITest\",\n \"appium:deviceName\": \"<Simulator_Name>\",\n \"appium:platformVersion\": \"<iOS_Version>\"\n}\n```","metadata":{"headerPath":"### Pre-Installed App (Real Device)","sectionCount":6,"filename":"capability-sets.md","relativePath":"appium-xcuitest-driver/docs/guides/capability-sets.md"}},{"pageContent":"---\ntitle: Continuous Integration\n---\n\nSetting up the XCUITest driver in an automated environment brings a few challenges with it. Any scenario\nwhere user interaction is required must be automated or avoided altogether. For real device setup,\nyou should first follow the [Real Device Configuration tutorial](../preparation/real-device-config.md).\n\n### Keychains\n\nOne common scenario is a prompt asking for a keychain to be unlocked in order to sign the WebDriverAgent.\nThere are multiple possible solutions for this:\n\n1. Keychains can be set to have no timeout and be unlocked manually once. This can be done using the\n keychain access application. Sometimes keychains still lock themselves though and this approach\n is not recommended.\n2. [It is possible to create a second keychain](../guides/troubleshooting.md#real-device-security-settings),\n which just stores the required certificate to sign the WebDriverAgent. The issue with this\n approach is that Codesign wants to unlock all listed keychains regardless of the specified\n keychain, thus leading to a password prompt. This can be avoided by setting the default keychain\n and basically hiding the login keychain at the start of the build.\n [See this Stackoverflow article](https://stackoverflow.com/questions/16550594/jenkins-xcode-build-works-codesign-fails)\n for how to utilize this approach. It is impractical when running other build jobs simultaneously.\n3. Stick with the existing keychains as in approach 1, but explicitly call unlock keychain before\n **each** build. This can be done using [fastlane unlock_keychain](https://docs.fastlane.tools/actions/unlock_keychain/)\n or by using [security unlock-keychain](https://www.unix.com/man-page/osx/1/security/) directly.\n The password can be saved as a CI variable/secret or on the machine itself.\n\nIt is recommended to go with the second or third option. The third one is the easiest and most\nreliable one to set up, at the cost of having to set the keychain password as an environment variable.\n\n### Xcode\n\nWhen setting up a new machine as a CI server, you are probably going to install Xcode, without\nexecuting it once, because you are not going to use it for development. Make sure to start Xcode at\nleast once and do the initial set up and install the suggested extensions.","metadata":{"headerPath":"","sectionCount":3,"filename":"ci-setup.md","relativePath":"appium-xcuitest-driver/docs/guides/ci-setup.md"}},{"pageContent":"### Linking Apple Account\n\nThis only applies for real device set up. Make sure to link your 'Apple Developer Account' in the\nmachine's system wide \"Account Panel\" when using the \"Basic Automatic Configuration\" described\n[here](../preparation/prov-profile-basic-auto.md).\n\n### Troubleshooting\n\nEnable the `appium:showXcodeLog` [capability](../reference/capabilities.md#webdriveragent) and\ncheck the Appium server output.","metadata":{"headerPath":"### Linking Apple Account","sectionCount":2,"filename":"ci-setup.md","relativePath":"appium-xcuitest-driver/docs/guides/ci-setup.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Get/Set Clipboard\n---\n\nWorking with the clipboard on real devices has an Apple security limitation, where the\nWebDriverAgentRunner application must be in foreground in order for the action to work. Otherwise\nan empty string is always returned, or it could raise an exception like\n[this issue](https://github.com/appium/appium/issues/18730).\n\nConsider using [`mobile: activateApp`](../reference/execute-methods.md/#mobile-activateapp)\nand [`mobile: backgroundApp`](../reference/execute-methods.md/#mobile-backgroundapp) to change the\nforeground application.\n\n## Get Clipboard\n\nApplies to iOS 13+ real devices. You can also use\n[`mobile: getPasteboard`](../reference/execute-methods.md#mobile-getpasteboard) for simulators.\n\n```ruby\n# Ruby\n\n# Bring the WebDriverAgent foreground. The bundle id depends on configuration such as \"appium:updatedWDABundleId\" for real devices.\ndriver.execute_script 'mobile: activateApp', {bundleId: 'com.facebook.WebDriverAgentRunner.xctrunner'}\n# Get the clipboard content\ndriver.get_clipboard\n# Go back to the application under test\ndriver.execute_script 'mobile: activateApp', {bundleId: '<bundle id of the test app>'}\n```\n\n## Set Clipboard\n\nApplies to iOS 15+ real devices. You can also use\n[`mobile: setPasteboard`](../reference/execute-methods.md#mobile-setpasteboard) for simulators.\n\n```ruby\n# Ruby\n\n# Bring the WebDriverAgent foreground. The bundle id depends on configuration such as \"appium:updatedWDABundleId\" for real devices.\ndriver.execute_script 'mobile: activateApp', {bundleId: 'com.facebook.WebDriverAgentRunner.xctrunner'}\n# Set the clipboard content\ndriver.set_clipboard(content: 'happy testing')\n# Go back to the application under test\ndriver.execute_script 'mobile: activateApp', {bundleId: '<bundle id of the test app>'}\n```","metadata":{"headerPath":"","sectionCount":3,"filename":"clipboard.md","relativePath":"appium-xcuitest-driver/docs/guides/clipboard.md"}},{"pageContent":"---\ntitle: Elements Lookup Troubleshooting\n---\n\nThis article helps to resolve possible issues that may pop up while looking up for elements with XCUITest driver,\nwhere the desired element is either not found or not visible in the page source at all.\n\nSince there might be multiple reasons to why an element cannot be found the topic is divided into sections where\neach section contains visible symptoms with the list of their possible resolutions.\n\n## Symptom #1\n\nThe desired element is shown as part of a bigger container and is not distinguishable in the page source tree.\nSometimes the whole application view with all elements in it is visible as one single container.\n\n## Resolutions To Symptom #1\n\n## Resolutions To Symptom #1 > ### Make sure the application under test is accessible\n\nThe XCUITest driver is based on Apple's XCTest framework. And the latter uses the information provided by the system\naccessibility framework to interact with on-screen elements, and to distinguish them. The same approach is used by\nvarious screen readers, VoiceOver, etc. You may start your journey into what Accessibility is and how to deal\nwith it in your applications from the official\n[Apple's accessibility guideline](https://developer.apple.com/design/human-interface-guidelines/accessibility).\nBear in mind, that this tutorial only describes apps based on official Apple frameworks, like UIKit or SwiftUI. If you\nuse a different framework to build the application's user interface, for example\n[React Native](https://reactnative.dev/), then consider looking for framework-specific accessibility guidelines.\nIt is also possible that the source tree displayed in Xcode accessibility inspector differs from the tree generated\nby XCTest. The best possible way to verify the page source generated by the latter is to check the output of the\n[debugDescription](https://developer.apple.com/documentation/xctest/xcuielement/1500909-debugdescription) attribute\nof the corresponding XCUIApplication element. XCUITest driver allows to perform a direct forwarding for this API by\nusing the [mobile: source](../reference/execute-methods.md#mobile-source) execute method with `format` set\nto `description`.","metadata":{"headerPath":"","sectionCount":4,"filename":"elements-lookup-troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/elements-lookup-troubleshooting.md"}},{"pageContent":"## Resolutions To Symptom #1 > ### Check if this is a hybrid application\n\nHybrid applications are applications that use\n[web views](https://developer.apple.com/design/human-interface-guidelines/web-views) in order to represent\ntheir whole user interface or portions of it.\nWeb views is the technology that allows to seamlessly integrate web pages browsing experience\ninto native mobile applications. Applications might contain native views mixed with web views, or the whole\napplication UI might be just a single web view. And while the built-in web view engine allows limited accessibility\ninteractions via [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) attributes, consider\nswitching a driver context instead in order to get full native access to the page DOM.\nRead [Automating Hybrid Apps](./hybrid.md) for more details there.\n\n## Resolutions To Symptom #1 > ### Make sure the application accessibility tree is not too deep\n\nApple's XCTest represents the page source as hierarchical structure (a tree), where each UI element has ancestor and\ndescendant relationships to other elements. There are applications having complex UI structure with deeply nested\nviews. Such deep structures are known to create problems for XCTest as the latter is unable to work with tree elements\nwhose nesting level is deeper than `62`. This limitation has to do with how `NSDictionary` works and cannot be worked\naround. The default maximum nesting level for the XCUITest driver is set to `50` and could be customized by the\n[snapshotMaxDepth](../reference/settings.md) setting.\n[React Native](https://reactnative.dev/) is known to create\nsuch deep hierarchies and the only viable solution for now is to fix the application\nunder test by flattening nested views. Check the corresponding [issue](https://github.com/appium/appium/issues/14825)\nfor more details.\nDeeply nested hierarchies might also be the reason for the element lookup slowness. Read the [Diagnosing WebDriverAgent Slowness](./wda-slowness.md) article to troubleshoot the latter.","metadata":{"headerPath":"## Resolutions To Symptom #1 > ### Check if this is a hybrid application","sectionCount":2,"filename":"elements-lookup-troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/elements-lookup-troubleshooting.md"}},{"pageContent":"## Resolutions To Symptom #1 > ### Make sure a valid active application is selected in WebDriverAgent\n\nSometimes, even if visually it looks like UI elements belong to the same application, they are referenced by\nabsolutely different apps. Moreover, the operating system\nmay change elements ownership in different versions. In the UI inspector it looks like visually the element\nis visible, but no \"real\" accessibility control relies on it. Most frequent candidates for such behavior are:\n- System alerts, for example camera or geolocation permission requests\n- Quick access toolbars, for example the one where Wi-Fi or Bluetooth state could be changed\n- Various RPC sheets, for example the Share To collection\n\nWebDriverAgent is designed the way it only interacts with a single app hierarchy at the particular\nmoment of time. Such application is called `active`.\nIt is possible to switch between applications in runtime using\n[mobile: activateApp](../reference/execute-methods.md#mobile-activateapp) API or\nto provide a hint for WebDriverAgent on which application to prefer if multiple apps are running\nusing the [defaultActiveApplication setting](../reference/settings.md).\nCheck the [Troubleshooting guide](./troubleshooting.md) and/or\n[Switching Between iOS Apps During a Test](https://appiumpro.com/editions/13-switching-between-ios-apps-during-a-test)\narticle for more details on how to make such elements available.\n\n## Symptom #2\n\nThe desired element is shown in the page tree, but cannot be found if looked up from an automated test.\n\n## Resolutions To Symptom #2","metadata":{"headerPath":"## Resolutions To Symptom #1 > ### Make sure a valid active application is selected in WebDriverAgent","sectionCount":3,"filename":"elements-lookup-troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/elements-lookup-troubleshooting.md"}},{"pageContent":"## Resolutions To Symptom #2 > ### Make sure there is no race condition\n\nSometimes the automation might too fast or too slow depending on in which state the UI is while the lookup is being\nexecuted. If it is too fast then consider using lookup timers, e.g. repeat the `findElement` more than once until\neither the element is found or the timeout occurs. All clients have convenience wrappers for such timers in form of\nexpected conditions.\nIf the automation is too slow, e.g. the desired element disappears faster than `findElement` could detect its presence\nthen make sure your script is optimized for the maximum performance, e.g. optimal/fast element locators are used,\nthe application itself and driver settings are [adjusted](./wda-slowness.md) to perform optimally, etc.\nThere might be situations where the automation framework is already optimized, although the desired element is\na short-living one, for example some notification popup that only appears for a second and then is immediately hidden.\nFor such \"special\" elements consider using approaches different from `findElement`, for example post-test video recording analysis (video FPS should usually be enough to catch all short-living elements), or introducing special\napplication debug settings to change the behavior for such elements and make them stay visible for longer time, or\nusing non-UI-related assertions, like logs analysis or direct API calls.\n\n## Resolutions To Symptom #2 > ### Make sure the debug environment matches to the testing one\n\nThere are known cases where application interface/behavior might differ in simulators and real devices. It might even differ\nif the screen size or device model/OS version/system setting differs. That is why always make sure your debug\nenvironment, for example one where Appium Inspector is used,\nis as close as possible to the environment where automated tests are being executed.\n\n## Symptom #3\n\nThe desired element is shown in the page tree, but its property value is not as expected, for example, it\nis shown as visible while one does not see it in the application interface or vice versa.\n\n## Resolutions To Symptom #3","metadata":{"headerPath":"## Resolutions To Symptom #2 > ### Make sure there is no race condition","sectionCount":4,"filename":"elements-lookup-troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/elements-lookup-troubleshooting.md"}},{"pageContent":"## Resolutions To Symptom #3 > ### XCUITest driver has minimum influence to attribute values\n\nThis is a simple and at the same time complicated topic. Since XCUITest driver is based on Apple's XCTest,\nall attribute values are retrieved from the latter. Standard attributes provided by XCTest could be found in\n[XCUIElementAttributes](https://developer.apple.com/documentation/xctest/xcuielementattributes?language=objc)\nprotocol reference. The full list of attributes supported by XCUITest driver's WebElement\ncould be found in the [Element Attributes](../reference/element-attributes.md) document.\nMost of the above attributes are simple compilations of standard attributes, for example, `elementType` is\ntranslated to `type` by matching the corresponding\n[enum](https://developer.apple.com/documentation/xctest/xcuielementtype?language=objc) value to a string representation, `name` is compiled from original element's identifier and label depending on what is\npresent first. The full list of mapping rules between standard and XCUITest attribute values could be found in\n[WebDriverAgent sources](https://github.com/appium/WebDriverAgent/blob/master/WebDriverAgentLib/Categories/XCUIElement%2BFBWebDriverAttributes.m).\nAlthough, some attributes there, like `visible` or `accessible` have no direct mapping in XCTest\nand are retrieved directly from the accessibility framework ~~using dark magic~~.\nThis means the actual value of these attributes only depends on accessibility internals and is there\nmostly due to ~~legacy~~ convenience purposes, as the original XCTest does not even expose them.\nWe'd love to deprecate and remove this legacy burden and only rely on officially supported attributes,\nalthough historically many people rely on them, so we keep it, even though their values might\nbe not reliable and there is no good way to debug this behavior or somehow influence it.\nThe final recommendation there would be:\n- If the value of an attribute that directly or indirectly relies on a public XCUIElement attribute\n is different from what you expect then run a vanilla XCTest with the same app and make sure\n it's not the same as you see in the XCUITest driver. If it is then the only place to complain\n would be the Apple support forum or a XCTest bug tracker. If you can confirm the issue lies in\n WebDriverAgent's mapping logic then feel free to raise an\n [issue](https://github.com/appium/WebDriverAgent/issues) to its maintainers.\n- If the value of an attribute that is a \"custom\" XCUITest attribute, like `visible` or `accessible`,","metadata":{"headerPath":"## Resolutions To Symptom #3 > ### XCUITest driver has minimum influence to attribute values","sectionCount":1,"recursiveSplit":true,"filename":"elements-lookup-troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/elements-lookup-troubleshooting.md"}},{"pageContent":"## Resolutions To Symptom #3 > ### XCUITest driver has minimum influence to attribute values\n\n[issue](https://github.com/appium/WebDriverAgent/issues) to its maintainers.\n- If the value of an attribute that is a \"custom\" XCUITest attribute, like `visible` or `accessible`,\n is different from what you expect then we, most likely, won't be able to help you. You may try\n to improve the corresponding WebDriverAgent sources, but keep in mind there are many automation\n tests around that rely on the current way these attributes are calculated, and we probably don't\n want to break them.","metadata":{"headerPath":"## Resolutions To Symptom #3 > ### XCUITest driver has minimum influence to attribute values","sectionCount":1,"recursiveSplit":true,"filename":"elements-lookup-troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/elements-lookup-troubleshooting.md"}},{"pageContent":"## Symptom #4\n\nThe desired element is shown in the page tree, but the content of its `value` property is cut off. For example, the actual size of the element's `value` attribute is above 512 bytes, while the size in the XML page source is always limited to 512 bytes.\n\n## Resolutions To Symptom #4\n\nRetrieve the element's `value` using the corresponding API ([Get Element Attribute](https://www.w3.org/TR/webdriver1/#get-element-attribute) / [Get Element Text](https://www.w3.org/TR/webdriver1/#dfn-get-element-text)) to get the full/uncut content. Please see [this issue](https://github.com/appium/appium-xcuitest-driver/issues/2552) and [this PR](https://github.com/appium/WebDriverAgent/pull/1007) for more details.\n\nXCTest framework cuts off long element values in snapshots to achieve the best performance and to reduce the memory footprint. If an element was inspected via [debugDescription](https://developer.apple.com/documentation/xctest/xcuielement/1500909-debugdescription) in XCTest for UI (not Appium XCUITest driver), it prints the value partially while the [value](https://developer.apple.com/documentation/xctest/xcuielementattributes/value) attribute like `element.value` prints the entire value.","metadata":{"headerPath":"## Symptom #4","sectionCount":2,"filename":"elements-lookup-troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/elements-lookup-troubleshooting.md"}},{"pageContent":"---\ntitle: File Transfer\n---\n\nThe XCUITest driver provides several [extension commands](../reference/execute-methods.md) for file transfer:\n\n* [`mobile: pullFolder`](../reference/execute-methods.md#mobile-pullfolder)\n* [`mobile: pullFile`](../reference/execute-methods.md#mobile-pullfile)\n* [`mobile: pushFile`](../reference/execute-methods.md#mobile-pushfile)\n* [`mobile: deleteFolder`](../reference/execute-methods.md#mobile-deletefolder)\n* [`mobile: deleteFile`](../reference/execute-methods.md#mobile-deletefile)\n\nThis documentation aims to help to understand how they work on iOS.\n\n## Formats\n\nAll commands require a parameter with a path to the file/folder on the target device. There are 3\npossible formats this path can take:\n\n## Formats > ### Format 1\n\n```\n@<app-bundle-id>:<container-type>/<path-to-file-or-folder>\n```\n\n* `@<app-bundle-id>` is the application bundle identifier\n* `<container-type>` is the container type\n * On simulators, common values are `app`, `data`, `groups`, but a custom one can also be provided\n * On real devices, the only accepted value is `documents`. All others are treated as Format 2\n * This value can only be specified for apps that have the `UIFileSharingEnabled` flag set to\n `true`. You can use the [`mobile: listApps`](../reference/execute-methods.md#mobile-listapps)\n extension to identify such apps.\n * By assigning the `skipDocumentsContainerCheck` [Settings API](https://appium.io/docs/en/latest/guides/settings/) to `true`, you may skip the above limitation for certain apps.\n\n* `<path-to-file-or-folder>` is the target file or folder\n * On real devices, if `<container-type>` is set to `documents`, this path will be mapped to\n `On My iPhone/<app name>` in the _Files_ app\n\n## Formats > ### Format 2\n\n```\n@<app-bundle-id>/<path-to-file-or-folder>\n```\n\n* On simulators, the implicit `<container-type>` is set to `app`.\n* On real device, only apps with the `UIFileSharingEnabled` flag set to `true` in their `info.plist`\n can be mounted. You can use the [`mobile: listApps`](../reference/execute-methods.md#mobile-listapps)\n extension to identify such apps.","metadata":{"headerPath":"","sectionCount":4,"filename":"file-transfer.md","relativePath":"appium-xcuitest-driver/docs/guides/file-transfer.md"}},{"pageContent":"## Formats > ### Format 3\n\n```\n<path-to-file-or-folder>\n```\n\nThis format is only supported on simulators. The implicit `<container-type>` is set to `app`.\nEventually the whole simulator file system is\n[available](https://stackoverflow.com/questions/6480607/is-there-any-way-to-see-the-file-system-on-the-ios-simulator)\ndirectly from the macOS Finder, so you may pull any file from there by providing a path to it\nrelatively to the simulator's file system root.\n\n## Examples\n\n## Examples > ### `pullFile`\n\nThis example pulls a file present in _Files -> On My iPhone -> Keynote_:\n\n|Top | On My iPhone | Keynote |\n|:----:|:----:|:----:|\n|![](./assets/images/ios-xctest-file-movement/top_files.png)|![](./assets/images/ios-xctest-file-movement/on_my_iphone.png)|![](./assets/images/ios-xctest-file-movement/keynote.png)|\n\n=== \"JS (WebdriverIO)\"\n\n ```javascript\n let data = driver.pullFile('@com.apple.Keynote:documents/Presentation.key');\n await fs.writeFile('presentation.key', Buffer.from(data, 'base64'), 'binary');\n ```\n\n=== \"Ruby\"\n\n ```ruby\n file = @driver.pull_file '@com.apple.Keynote:documents/Presentation.key'\n File.open('presentation.key', 'wb') { |f| f<< file }\n ```\n\nIf the file is in deeper place like _Keynote/Dir1/Dir2_, then the path changes:\n\n=== \"JS (WebdriverIO)\"\n\n ```javascript\n let data = driver.pullFile('@com.apple.Keynote:documents/Dir1/Dir2/Presentation.key');\n await fs.writeFile('presentation.key', Buffer.from(data, 'base64'), 'binary');\n ```\n\n=== \"Ruby\"\n\n ```ruby\n file = @driver.pull_file '@com.apple.Keynote:documents/Dir1/Dir2/Presentation.key'\n File.open('presentation.key', 'wb') { |f| f<< file }\n ```\n\nExample for a simulator using Format 3:\n\n```java\n// Java\n// Get AddressBook.sqlitedb in test app package ('app' container)\nbyte[] fileContent = driver.pullFile(\"Library/AddressBook/AddressBook.sqlitedb\");\nPath dstPath = Paths.get(new File(\"/local/path/AddressBook.sqlitedb\"));\nFiles.write(dstPath, fileContent);\n```\n\n## Examples > ### `pullFolder`\n\nYou can pull folders similarly to files, but the path must end with a forward slash (`/`).\n\n=== \"JS (WebdriverIO)\"\n\n ```javascript\n let data = driver.pullFolder('@com.apple.Keynote:documents/');\n await fs.writeFile('documents.zip', Buffer.from(data, 'base64'), 'binary');\n ```\n\n=== \"Ruby\"\n\n ```ruby\n file = @driver.pull_folder '@com.apple.Keynote:documents/'\n File.open('documents.zip', 'wb') { |f| f<< file }\n ```","metadata":{"headerPath":"## Formats > ### Format 3","sectionCount":4,"filename":"file-transfer.md","relativePath":"appium-xcuitest-driver/docs/guides/file-transfer.md"}},{"pageContent":"## Examples > ### `pushFile`\n\n=== \"JS (WebdriverIO)\"\n\n ```javascript\n driver.pushFile('@com.apple.Keynote:documents/text.txt', new Buffer(\"Hello World\").toString('base64'));\n ```\n\n=== \"Ruby\"\n\n ```ruby\n @driver.push_file '@com.apple.Keynote:documents/text.txt', (File.read 'path/to/file')\n ```\n\n## References\n\n- <https://stackoverflow.com/questions/1108076/where-does-the-iphone-simulator-store-its-data>\n- <https://stackoverflow.com/questions/48884248/how-can-i-add-files-to-the-ios-simulator>\n- <https://apple.stackexchange.com/questions/299413/how-to-allow-the-files-app-to-save-to-on-my-iphone-or-to-on-my-ipad-in-ios/299565#299565>","metadata":{"headerPath":"## Examples > ### `pushFile`","sectionCount":2,"filename":"file-transfer.md","relativePath":"appium-xcuitest-driver/docs/guides/file-transfer.md"}},{"pageContent":"---\ntitle: Gestures\n---\n\nThe XCUITest driver provides multiple options for touch gestures automation.\nFor simple gestures, like tap by coordinates, long tap, multi-finger tap, double/triple tap,\nswipe, drag, rotate, scroll or pinch use the below gesture shortcuts:\n\n- [mobile: tap](../reference/execute-methods.md#mobile-tap)\n- [mobile: doubleTap](../reference/execute-methods.md#mobile-doubletap)\n- [mobile: touchAndHold](../reference/execute-methods.md#mobile-touchandhold)\n- [mobile: twoFingerTap](../reference/execute-methods.md#mobile-twofingertap)\n- [mobile: dragFromToForDuration](../reference/execute-methods.md#mobile-dragfromtoforduration)\n- [mobile: dragFromToWithVelocity](../reference/execute-methods.md#mobile-dragfromtowithvelocity)\n- [mobile: rotateElement](../reference/execute-methods.md#mobile-rotateelement)\n- [mobile: tapWithNumberOfTaps](../reference/execute-methods.md#mobile-tapwithnumberoftaps)\n- [mobile: forcePress](../reference/execute-methods.md#mobile-forcepress)\n- [mobile: scrollToElement](../reference/execute-methods.md#mobile-scrolltoelement)\n- [mobile: scroll](../reference/execute-methods.md#mobile-scroll)\n- [mobile: pinch](../reference/execute-methods.md#mobile-pinch)\n\nFor more sophisticated gestures\nconsider using [W3C actions](https://w3c.github.io/webdriver/#actions).\n\nMake sure you don't use deprecated JSONWP TouchActions APIs. They have been\nremoved from the XCUITest driver since version 7.\n\nIf the action code in the client source looks good and satisfies the above requirements,\nbut its execution still does not deliver the expected result then the following debugging\nmeasures might be applied:","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"gestures.md","relativePath":"appium-xcuitest-driver/docs/guides/gestures.md"}},{"pageContent":"- Make sure the gesture has valid coordinates and respects pauses between pointer state changes.\n For example, it is always mandatory to provide a valid element or valid `absolute` coordinates\n to any gesture at the beginning. iOS only registers\n a long touch/click if the pointer has been depressed for longer than 500ms. For shorter actions\n a simple click is registered instead.\n- If your tests run on Simulator then it is possible to activate pointer tracing by enabling\n the [appium:simulatorTracePointer](../reference/capabilities.md#simulator) capability or by enabling\n `Visual Indicators` items from Simulator settings. After running\n your automation code with this feature enabled you would be able to see the exact pointer trace path\n and check the velocity of the gesture. Compare the trace\n to how the same gesture is usually done manually and apply the necessary updates to your code.\n- Do not mix webview and native elements in actions arguments. It simply won't work. Native\n actions could only consume native elements. A single possibility to perform a native action\n on a web element would be to translate its coordinates into the native context and pass these\n coordinates as native action arguments.\n\nCheck the below tutorials for more details on how to build reliable action chains:\n\n- [Automating Complex Gestures with the W3C Actions API](https://appiumpro.com/editions/29-automating-complex-gestures-with-the-w3c-actions-api)\n- [Swiping your way through Appium by Wim Selles #AppiumConf2021](https://www.youtube.com/watch?v=oAJ7jwMNFVU)\n- [About iOS Input Events](./input-events.md)","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"gestures.md","relativePath":"appium-xcuitest-driver/docs/guides/gestures.md"}},{"pageContent":"---\ntitle: Automating Hybrid Apps\n---\n\nOne of the core principles of XCUITest driver is that you shouldn't have to change your\napp to test it. In line with that methodology, it is possible to test hybrid\napps the same way you can with Selenium for web apps. There is a bit of technical\ncomplexity required so that XCUITest driver knows whether you want to automate the native\naspects of the app or the web views. But, thankfully, we can stay within the\nSelenium WebDriver protocol for everything.\n\nOnce the test is in a web view context the command set that is available is the\nfull [Selenium](http://www.seleniumhq.org/) [WebDriver API](https://www.w3.org/TR/webdriver/).\n\n### Requirements\n\nTo interact with a web view XCUITest driver establishes a connection using a custom\n[remote debugger](https://github.com/appium/appium-remote-debugger).\nThis debugger can connect directly to any WebKit debugger socket exposed by the system.\nThe protocol used for the communication there is a proprietary Apple's JSON RPC similar\nto Chrome's [Devtools Protocol](https://chromedevtools.github.io/devtools-protocol/).\nNot all web views expose debugger web sockets by default thus making them invisible\nfor the XCUITest driver and not showing in the available contexts list.\nMake sure the following prerequisites are satisfied if you are unsure about whether\nthe particular web view is debuggable or not:\n\n- If you use real devices then make sure the Settings→Safari→Advanced→Web Inspector\n checkbox is turned on.\n- If your app's web view is based on WKWebView then make sure the\n [isInspectable](https://developer.apple.com/documentation/webkit/wkwebview/4111163-inspectable?language=objc) property of it set to `true`. Note, that you must have access to the application sources in order\n to ensure that!\n- Make sure you see the corresponding web view in Safari's\n [remote debugger](https://help.salesforce.com/s/articleView?id=000391692&type=1) list.\n\nIf all the above requirements have been satisfied, but the desired web view is still not present in the\nXCUITest driver's context list then there is probably an issue in the driver itself, which must be reported\nto driver maintainers.","metadata":{"headerPath":"","sectionCount":2,"filename":"hybrid.md","relativePath":"appium-xcuitest-driver/docs/guides/hybrid.md"}},{"pageContent":"### Entering the web view context\n\nHere are the steps required to talk to a web view in your XCUITest driver test:\n\n1. Navigate to a portion of your app where a web view is active\n2. Retrieve the currently available contexts\n * This returns a list of contexts we can access, like `'NATIVE_APP'` or `'WEBVIEW_1'`\n3. Set the id of the context you want to access\n * This puts your XCUITest session into a mode where all commands are\n interpreted as being intended for automating the web view, rather than the\n native portion of the app. For example, if you run `findElement`, it\n will operate on the DOM of the web view, rather than return native elements.\n Of course, certain WebDriver methods only make sense in one context or\n another, so in the wrong context you will receive an error message.\n4. To stop automating in the web view context and go back to automating the\n native portion of the app, simply set the context\n again with the native context id (generally `'NATIVE_APP'`) to leave the web\n context and once again access the native commands.\n\n### Automatically entering the web view context on session start\n\nIf your application begins in a web view, and you do not want to automate the\nnative application before entering it, you can have XCUITest driver automatically enter\nthe web view context on session initialization by setting the `autoWebview`\n[capability](../reference/capabilities.md) to `true`.","metadata":{"headerPath":"### Entering the web view context","sectionCount":2,"filename":"hybrid.md","relativePath":"appium-xcuitest-driver/docs/guides/hybrid.md"}},{"pageContent":"### Examples\n\n=== \"Java\"\n ```java\n // java\n // assuming we have a set of capabilities\n driver = new AppiumDriver(new URL(\"http://127.0.0.1:4723/\"), options);\n\n Set<String> contextNames = driver.getContextHandles();\n for (String contextName : contextNames) {\n System.out.println(contextName); //prints out something like NATIVE_APP \\n WEBVIEW_1\n }\n driver.context(contextNames.toArray()[1]); // set context to WEBVIEW_1\n\n //do some web testing\n String myText = driver.findElement(By.cssSelector(\".green_button\")).click();\n\n driver.context(\"NATIVE_APP\");\n\n // do more native testing if we want\n\n driver.quit();\n ```\n \n=== \"Ruby\"\n ```ruby\n # ruby_lib_core\n # assuming we have a set of capabilities\n @driver = Appium::Core.for(url: SERVER_URL, desired_capabilities: capabilities).start_driver\n # ruby_lib\n # opts = { caps: capabilities, appium_lib: { custom_url: SERVER_URL }}\n # @driver = Appium::Driver.new(opts, true).start_driver\n\n # I switch to the last context because its always the webview in our case, in other cases you may need to specify a context\n # View the appium logs while running @driver.contexts to figure out which context is the one you want and find the associated ID\n # Then switch to it using @driver.switch_to.context(\"WEBVIEW_6\")\n\n Given(/^I switch to webview$/) do\n webview = @driver.available_contexts.last\n @driver.switch_to.context(webview)\n end\n\n Given(/^I switch out of webview$/) do\n @driver.switch_to.context(@driver.contexts.first)\n end\n\n # Now you can use CSS to select an element inside your webview\n\n And(/^I click a webview button $/) do\n @driver.find_element(:css, \".green_button\").click\n end\n ```\n\n=== \"Python\"\n ```python\n # python\n # assuming we have an initialized `driver` object for an app\n\n # switch to webview\n webview = driver.contexts.last\n driver.switch_to.context(webview)\n\n # do some webby stuff\n driver.find_element(By.CSS, \".green_button\").click\n\n # switch back to native view\n driver.switch_to.context(driver.contexts.first)\n\n # do more native testing if we want\n\n driver.quit()\n ```","metadata":{"headerPath":"### Examples","sectionCount":1,"filename":"hybrid.md","relativePath":"appium-xcuitest-driver/docs/guides/hybrid.md"}},{"pageContent":"---\ntitle: About iOS Input Events\n---\n\n## What Are Input Events\n\niOS uses the Events concept to handle signals received from different input devices. An Event is an\nobject generated in response to a signal from an input device. These objects are then delivered to\nthe corresponding kernel subsystem, which processes them and notifies all listening processes about\ntaps, key presses, swipes, etc. This means that in order to emulate a signal generated by an external\ndevice, such as a touch screen, it is necessary to just send Event objects with the same properties\nand in the same sequence as they would be generated by a real device.\n\n## Simulating a Single Tap\n\nThe Events API itself is a part of Apple private API, and it is neither open sourced nor documented.\nThe XCTest framework also does not expose any _public_ APIs for input events generation, although\nthere is a possibility to perform events generation via XCTest _private_ undocumented APIs.\n\nIn particular, we are interested in the\n[`XCPointerEventPath`](https://github.com/appium/WebDriverAgent/blob/master/PrivateHeaders/XCTest/XCPointerEventPath.h)\nand [`XCSynthesizedEventRecord`](https://github.com/appium/WebDriverAgent/blob/master/PrivateHeaders/XCTest/XCSynthesizedEventRecord.h)\ninterfaces. These APIs allow to create chains of input events and supply them to the system kernel\nfor execution.\n\nIn order to synthesize a single tap, it is necessary to:\n\n- Create a new `XCPointerEventPath` instance and initialize it for touch at the starting point\n- Add a new `liftUp` event at `0.125s` offset using `liftUpAtOffset:` method\n- Add the generated event path object to `XCSynthesizedEventRecord` instance using\n `addPointerEventPath:` method\n- Execute the events using `synthesizeWithError:` method of `XCSynthesizedEventRecord` instance and\n control the returned error\n\nThere are several limitations to these APIs:\n\n- Each `XCPointerEventPath` instance can only be executed for a single action. If one tries to add,\n for example, two taps to a single path, then these are effectively ignored\n- Each `XCPointerEventPath` instance can only be initialized for a particular pointer type: touch,\n mouse (since Xcode 10.2) or keyboard (since Xcode 10.2)\n- Events can only be added with increasing offset values to an existing `XCPointerEventPath` instance","metadata":{"headerPath":"","sectionCount":3,"filename":"input-events.md","relativePath":"appium-xcuitest-driver/docs/guides/input-events.md"}},{"pageContent":"## More Complicated Actions\n\nUnfortunately, because the API is private and has zero documentation, one can only figure out what\nit can do by playing with it and trying different input combinations.\n\nIt is known that providing multiple `XCPointerEventPath` instances with overlapping timeouts will\ngenerate a multitouch action with the amount of fingers equal to the amount of the supplied event\npaths. So, in order to generate two-finger symmetric swipe we need to supply the following events:\n\n- Create a two `XCPointerEventPath` instances and init them for touch at the starting point\n- Add a `moveToPoint` event at `0.525s` offset using `moveToPoint:` method to each path\n- Add a `liftUp` eventa at `0.525s` offset using `liftUpAtOffset:` method to each path\n- Add the generated event paths to `XCSynthesizedEventRecord` instance using `addPointerEventPath:` method\n- Execute the events using `synthesizeWithError:` method of `XCSynthesizedEventRecord` instance and\n control the returned error\n\n## Further Reading\n\nUnfortunately, there is no information on this topic at all (private API `¯\\_(ツ)_/¯`). Consider\nvisiting the following resources:\n\n* <https://github.com/appium/WebDriverAgent/tree/master/PrivateHeaders/XCTest>\n* <https://github.com/appium/WebDriverAgent/blob/master/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m>\n* <https://github.com/appium/WebDriverAgent/blob/master/WebDriverAgentTests/IntegrationTests/FBW3CMultiTouchActionsIntegrationTests.m>\n* <https://github.com/appium/WebDriverAgent/blob/master/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m>","metadata":{"headerPath":"## More Complicated Actions","sectionCount":2,"filename":"input-events.md","relativePath":"appium-xcuitest-driver/docs/guides/input-events.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Self-Signed Certificates\n---\n\nUnfortunately, Apple does not provide any command line options which can help to install self-signed\ncertificate on a real device or simulator. However, there is\n[over-the-air](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/Introduction/Introduction.html)\nenrollment technology, which allows the deployment of several entity types, including such\ncertificates, by simply downloading specially prepared configuration files with the built-in web\nbrowser. After the configuration is downloaded it can be installed and trusted by going through\nseveral simple wizard steps.\n\nYou can use the following extension methods to assist with this:\n\n* [`mobile: installCertificate`](../reference/execute-methods.md#mobile-installcertificate)\n* [`mobile: removeCertificate`](../reference/execute-methods.md#mobile-removecertificate)","metadata":{"headerPath":"","sectionCount":1,"filename":"install-certificate.md","relativePath":"appium-xcuitest-driver/docs/guides/install-certificate.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Managing Multiple Xcodes\n---\n\nIf you have multiple Xcode installations, you may choose which toolset Appium should use with one\nof two ways:\n\n### `xcode-select` tool\n\nOnly available with `sudo` privileges, affects the whole system.\n\nAssuming you want to choose `/Applications/Xcode13.app`:\n\n1. Set the default Xcode\n ```\n sudo xcode-select -s /Applications/Xcode13.app/Contents/Developer\n ```\n2. Run Appium\n ```\n appium\n ```\n\n### Environment variable\n\nNo privileges needed, affects only the current shell, so Appium should be started within that shell.\n\nAssuming you want to choose `/Applications/Xcode12.app`:\n\n1. Set the `DEVELOPER_DIR` environment variable\n ```\n export DEVELOPER_DIR=/Applications/Xcode12.app/Contents/Developer\n ```\n2. Run Appium\n ```\n appium\n ```","metadata":{"headerPath":"","sectionCount":3,"filename":"multiple-xcode-versions.md","relativePath":"appium-xcuitest-driver/docs/guides/multiple-xcode-versions.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Testing in Parallel\n---\n\nIt is possible to execute tests in parallel using XCUITest driver. Appium allows to do this on a\nper-process (multiple server processes running on different ports managing single session) or a\nper-request basis (single server process managing multiple sessions, more preferable, uses less\nresources and ensures better control over running sessions).\n\n!!! note\n\n If you are _not_ going to run your tests in parallel, consider enabling the `--session-override`\n Appium server argument. It forces the server to close all pending sessions before a new one\n could be opened, which allows you to avoid possible issues with such sessions silently\n running/expiring in the background.\n\n### Important Real Device Capabilities\n\n- `udid` must be a unique device UDID for each parallel session.\n- `wdaLocalPort` must be a unique port number for each parallel session. The default value is `8100`.\n- `derivedDataPath` set the unique derived data path root for each driver instance. This will help\n to avoid possible conflicts and to speed up the parallel execution.\n- `mjpegServerPort` must be a unique port number for each parallel session if you are going to\n record a video stream from it. The default value is `9100`.\n\n### Important Simulator Capabilities\n\n- Either `udid`, which is the unique simulator UDID for each parallel session (it could be retrieved\n from `xcrun simctl list` command output), or a unique combination of `deviceName` and\n `platformVersion` capabilities to identify the appropriate simulator with the given name and\n version number for each parallel session.\n- `wdaLocalPort` must be a unique port number for each parallel session. The default value is `8100`.\n- `derivedDataPath` set the unique derived data path root for each driver instance. This will help\n to avoid possible conflicts and to speed up the parallel execution.\n- `mjpegServerPort` must be a unique port number for each parallel session if you are going to\n record a video stream from it. The default value is `9100`.","metadata":{"headerPath":"","sectionCount":3,"filename":"parallel-tests.md","relativePath":"appium-xcuitest-driver/docs/guides/parallel-tests.md"}},{"pageContent":"---\ntitle: Run Prebuilt WebDriverAgentRunner\n---\n\nThe XCUITest driver runs `xcodebuild` to build and install the WebDriverAgentRunner (WDA) app on the\ntarget device. Running the command every time could slow down new session creation.\nYou can manually run a modified version of this command in order to prebuild the WDA.\n\n## Understanding How `xcodebuild` Works\n\nBy default, `xcodebuild` is run with two commands: `build-for-testing` and `test-without-building`.\n`build-for-testing` builds a test bundle package, whereas `test-without-building` actually runs it.\n\nFor instance, XCUITest driver issues an `xcodebuild` command like so:\n\n```bash\nxcodebuild build-for-testing test-without-building \\\n -project WebDriverAgent.xcodeproj \\\n -derivedDataPath wda_build \\\n -scheme WebDriverAgentRunner \\\n -destination \"platform=iOS Simulator,name=iPhone 14 Pro\" \\\n CODE_SIGNING_ALLOWED=NO\n```\n\nThis translates to `xcodebuild` building `WebDriverAgent.xcodeproj` and running the resulting\npackage on the specified device. The built package will be located in the `wda_build` path.\n\nThe command can be split into `build-for-testing` and `test-without-building` parts as follows:\n\n```bash\nxcodebuild build-for-testing \\\n -project WebDriverAgent.xcodeproj \\\n -derivedDataPath wda_build \\\n -scheme WebDriverAgentRunner \\\n -destination \"platform=iOS Simulator,name=iPhone 14 Pro\" \\\n CODE_SIGNING_ALLOWED=NO\n```\n\n```bash\nxcodebuild test-without-building \\\n -xctestrun wda_build/Build/Products/WebDriverAgentRunner_iphonesimulator16.2-arm64.xctestrun \\\n -destination \"platform=iOS Simulator,name=iPhone 14 Pro\"\n```\n\n* The `build-for-testing` command generates two files: an `.app` package and an `.xctestrun` file, e.g.:\n\n ```\n wda_build/Build/Products/Debug-iphonesimulator/WebDriverAgentRunner-Runner.app\n wda_build/Build/Products/WebDriverAgentRunner_iphonesimulator16.2-arm64.xctestrun\n ```\n\n The `.xctestrun` file name depends on the `-destination` preference. The file contains metadata\n about the package (the `DependentProductPaths` key).\n\n* The `test-without-building` command starts the WDA application for testing by referencing the\n provided `.xctestrun` file. Once this is done, `http://localhost:8100` will be able to receive\n commands for the target device.\n\n## Preparation performance improvement ideas","metadata":{"headerPath":"","sectionCount":3,"filename":"run-prebuilt-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/run-prebuilt-wda.md"}},{"pageContent":"## Preparation performance improvement ideas > ### Download Prebuilt WDA and run them with `appium:prebuiltWDAPath` and `appium:usePreinstalledWDA`\n\nThis approach allows the XCUITest driver to start WDA without running `xcodebuild` by using prebuilt WDA packages.\nWe recommend this method if you don't need to modify the WDA source code.\n\n[The Appium WebDriverAgent GitHub page](https://github.com/appium/WebDriverAgent/releases) provides\ndownloads for WebDriverAgent packages for real devices and simulators.\nWebDriverAgent packages for real devices do not have embedded XCTest frameworks so that\nthey can run on iOS 17+ devices. Please read [Run Preinstalled WebDriverAgentRunner](./run-preinstalled-wda.md)\nfor more details about running on real devices. Understanding app signing is also important when working with real devices.\nSimulators need everything, so WDA package sizes for simulators are greater than for real devices.\nThe [Release](https://github.com/appium/appium-xcuitest-driver/actions/workflows/publish.js.yml) and\n[Building WebDriverAgent](https://github.com/appium/WebDriverAgent/actions/workflows/wda-package.yml)\nworkflows may help with validating the build script.\n\n[Run Preinstalled WebDriverAgentRunner](./run-preinstalled-wda.md) provides `appium:prebuiltWDAPath`\nand `appium:usePreinstalledWDA` capabilities.\nThese capabilities allow the XCUITest driver to install prebuilt WDA specified with\n`appium:prebuiltWDAPath` and start it **without** running `xcodebuild`.\n\nThe `download-wda-sim` command helps to download the proper version of WDA for your XCUITest driver version\nfor simulator use.\n\n```bash\nappium driver run xcuitest download-wda-sim --outdir=/path/to/target/directory\n```\n\nThen, starting a new session with capabilities below:\n\n```json\n{\n \"appium:usePreinstalledWDA\": true,\n \"appium:prebuiltWDAPath\": \"/path/to/target/directory/WebDriverAgentRunner-Runner.app\"\n}\n```\n\nThe new session starts without an `xcodebuild` run.","metadata":{"headerPath":"## Preparation performance improvement ideas > ### Download Prebuilt WDA and run them with `appium:prebuiltWDAPath` and `appium:usePreinstalledWDA`","sectionCount":1,"filename":"run-prebuilt-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/run-prebuilt-wda.md"}},{"pageContent":"## Preparation performance improvement ideas > ### Capabilities for Prebuilt WDA with `appium:useXctestrunFile`, `appium:usePrebuiltWDA` or `appium:prebuildWDA`\n\nThe XCUITest driver provides two capabilities that allow skipping the `build-for-testing` command,\nand executing only the `test-without-building` command: __`appium:useXctestrunFile`__ and\n__`appium:bootstrapPath`__ (see [Capabilities](../reference/capabilities.md#webdriveragent)).\n\n!!! note\n\n These capabilities expect that the WDA files are already prebuild, so make sure to first run\n `xcodebuild` to create the files.\n\nThis method can be used on both real devices and simulators, but real devices requires proper\nsigning as described in [Run Preinstalled WebDriverAgentRunner](./run-preinstalled-wda.md).\n\nThe capabilities can be used as follows:\n\n```json\n{\n \"platformName\": \"ios\",\n \"appium:automationName\": \"xcuitest\",\n \"appium:platformVersion\": \"18.4\",\n \"appium:deviceName\": \"iPhone 16\",\n \"appium:useXctestrunFile\": true,\n \"appium:bootstrapPath\": \"/path/to/wda_build/Build/Products\"\n}\n```\n\nNot all combinations have been tested, but the target device can probably be anything.\n\nThe same thing can be achieved with the __`appium:derivedDataPath`__ and __`appium:usePrebuiltWDA`__\ncapabilities, but this may fail if `xcodebuild` cannot find or handle the `.xctestrun` file\nproperly. The stability depends on Xcode.\n\n__`appium:prebuildWDA`__ lets the XCUITest driver build the WDA before running it, then the session\nwill be handled with `appium:usePrebuiltWDA`.\nIt might have additional building steps than with `appium:derivedDataPath` and `appium:usePrebuiltWDA`\ncombination, but it could help `appium:usePrebuiltWDA` to not manage the WDA project.","metadata":{"headerPath":"## Preparation performance improvement ideas > ### Capabilities for Prebuilt WDA with `appium:useXctestrunFile`, `appium:usePrebuiltWDA` or `appium:prebuildWDA`","sectionCount":1,"filename":"run-prebuilt-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/run-prebuilt-wda.md"}},{"pageContent":"---\ntitle: Run Preinstalled WebDriverAgentRunner\n---\n\nThe XCUITest driver can be configured to launch an already-installed `WebDriverAgentRunner-Runner`\napplication (WDA) on a real device and a simulator. This allows you to start a session without the `xcodebuild`\ncommand execution, improving the session startup performance.\n\n!!! warning\n\n iOS/tvOS 17+ specific:\n\n This method currently works over `devicectl` for iOS 17+ with Xcode 15+ environment since XCUITest driver v7.5.0.\n This may not work for tvOS 17+.\n iOS/tvOS 16 and lower ones work over [appium-ios-device](https://github.com/appium/appium-ios-device) directly.\n\n## Capabilities\n\n- Required\n - [`appium:usePreinstalledWDA`](../reference/capabilities.md#webdriveragent)\n- Optional\n - [`appium:updatedWDABundleId`](../reference/capabilities.md#webdriveragent)\n - [`appium:updatedWDABundleIdSuffix`](../reference/capabilities.md#webdriveragent)\n - Since XCUITest driver v7.6.0\n - [`appium:prebuiltWDAPath`](../reference/capabilities.md#webdriveragent)\n\n## Install WebDriverAgent\n\n## Install WebDriverAgent > ### Using Xcode\n\nRunning a test for the WDA package in Xcode is the easiest way to prepare the device environment:\n\n1. Open WebDriverAgent project in Xcode\n - You can run `appium driver run xcuitest open-wda` if using XCUITest driver 4.13 or newer\n2. Select the _WebDriverAgentRunner_ scheme\n3. Select the scheme as _Product -> Scheme -> WebDriverAgentRunner_ (or _WebDriverAgentRunner\\_tvOS_ for tvOS)\n4. Select your device in _Product -> Destination_\n5. Select _Product -> Test_ to build and install the WDA app\n\nIf using a real device, you may need to change your bundle ID. Please check the\n[Full Manual Provisioning Profile setup](../preparation/prov-profile-full-manual.md) for details.","metadata":{"headerPath":"","sectionCount":4,"filename":"run-preinstalled-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/run-preinstalled-wda.md"}},{"pageContent":"## Install WebDriverAgent > ### Using 3rd Party Tools\n\nSome 3rd party tools such as [pymobiledevice3](https://github.com/doronz88/pymobiledevice3),\n[ios-deploy](https://github.com/ios-control/ios-deploy), [go-ios](https://github.com/danielpaulus/go-ios) and\n[tidevice](https://github.com/alibaba/taobao-iphone-device), [ios-app-signer](https://github.com/DanTheMan827/ios-app-signer)\ncan install the WebDriverAgent package.\n\nSome tools let you set an arbitrary bundle identifier (`CFBundleIdentifier` for the `Info.plist`) and sign it with the bundle identifier.\nIt may not have `.xctrunner` as the bundle identifier.\nXCUITest driver automatically adds the `.xctrunner` suffix to the provided bundle identifier unless a different suffix is specified by the `appium:updatedWDABundleIdSuffix` capability.\nIf the value is an empty string, then no suffix will be added to the provided bundle identifier.\n\nThe WDA app package (`WebDriverAgentRunner-Runner.app`) can be generated in the _derivedDataPath_\ndirectory, as explained in [Manual Configuration for a Generic Device](../preparation/prov-profile-generic-manual.md).\nThe app can then be installed without `xcodebuild` using the 3rd party tools.","metadata":{"headerPath":"## Install WebDriverAgent > ### Using 3rd Party Tools","sectionCount":1,"filename":"run-preinstalled-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/run-preinstalled-wda.md"}},{"pageContent":"## Install WebDriverAgent > ### Additional requirement for iOS 17+/tvOS17+\n\nTo launch the WebDriverAgentRunner package with `xcrun devicectl device process launch` for real devices it should not have `Frameworks/XC**` files.\n\nFor example, after building the WebDriverAgent with Xcode with proper sign, it generates `/Users/<user>/Library/Developer/Xcode/DerivedData/WebDriverAgent-ezumztihszjoxgacuhatrhxoklbh/Build/Products/Debug-appletvos/WebDriverAgentRunner-Runner.app`.\nThen you can remove `Frameworks/XC**` in `WebDriverAgentRunner-Runner.app` like `rm Frameworks/WebDriverAgentRunner-Runner.app/XC**`.\n\nConfiguring `appium:prebuiltWDAPath` to the `/Users/<user>/Library/Developer/Xcode/DerivedData/WebDriverAgent-ezumztihszjoxgacuhatrhxoklbh/Build/Products/Debug-appletvos/WebDriverAgentRunner-Runner.app` would install the `WebDriverAgentRunner-Runner.app`, which has no `Frameworks/XC**` to the target device and launch it with `devicectl` command as part of `appium:usePreinstalledWDA` functionality.\n\n!!! note\n\n You can also remove `Frameworks/Testing.framework` and `Frameworks/libXCTestSwiftSupport.dylib` to reduce the package size\n because WebDriverAgent doesn't need both. Then, the total size of the WebDriverAgent runner app can be 3MB or less.\n `Testing.framework` is almost 6MB and `libXCTestSwiftSupport.dylib` is 2.6MB with Xcode 16 build.","metadata":{"headerPath":"## Install WebDriverAgent > ### Additional requirement for iOS 17+/tvOS17+","sectionCount":1,"filename":"run-preinstalled-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/run-preinstalled-wda.md"}},{"pageContent":"## Launch the Session\n\nAfter installing the `WebDriverAgentRunner-Runner` application, you can start the Appium server\nand launch an XCUITest driver session with the specified capabilities:\n\n```\nappium\n```\n\n```ruby\n# Ruby\ncapabilities: {\n \"platformName\": \"ios\",\n \"appium:automationName\": \"xcuitest\",\n \"appium:udid\": \"<udid>\",\n \"appium:usePreinstalledWDA\": true,\n \"appium:updatedWDABundleId\": \"com.appium.WebDriverAgentRunner\"\n}\n@core = Appium::Core.for capabilities: capabilities\ndriver = @core.start_driver\n# do something\ndriver.quit\n```\n\nIf the `<udid>` device has a WebDriverAgent package with `com.appium.WebDriverAgentRunner.xctrunner`\nbundle ID, the session will launch the WebDriverAgent process without `xcodebuild`.\n\n!!! note\n\n Please ensure that the WDA application is launchable before starting an XCUITest driver session.\n For example, check whether the provisioning profile is trusted.\n\n\n!!! note\n\n Please make sure the device under test has the developer disk image mounted.\n This is necessary to start an XCTest session and load the required XCTest libraries from the device.\n For example, starting Xcode after connecting the device to the host machine will mount the developer disk image automatically.\n Using third-party tools can also help to mount the developer disk image service.\n Please check the documentation for each tool to understand how to mount the developer disk image.\n\n\n```ruby\n# Ruby\ncapabilities: {\n \"platformName\": \"ios\",\n \"appium:automationName\": \"xcuitest\",\n \"appium:udid\": \"<udid>\",\n \"appium:usePreinstalledWDA\": true,\n \"appium:updatedWDABundleId\": \"io.appium.wda\"\n \"appium:updatedWDABundleIdSuffix\": \"\"\n}\n@core = Appium::Core.for capabilities: capabilities\ndriver = @core.start_driver\n# do something\ndriver.quit\n```\n\nIf the `<udid>` device has a WebDriverAgent package with `io.appium.wda` bundle ID (it does not have `.xctrunner`),\nthe session will launch the WebDriverAgent process without `xcodebuild`.","metadata":{"headerPath":"## Launch the Session","sectionCount":1,"filename":"run-preinstalled-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/run-preinstalled-wda.md"}},{"pageContent":"## Set `appium:prebuiltWDAPath`\n\nIf the `appium:prebuiltWDAPath` capability is provided with a `WebDriverAgentRunner-Runner.app` test bundle,\nthe XCUITest driver will install the application and launch it every test session.\nTest bundles cannot be versioned using `CFBundleVersion` as vanilla applications do usually,\nwhich is why it is necessary to (re)install them for every test session.\nThe test bundle should be signed properly for real devices.\n\nUsually you can find the WDA application bundle at the below location if you use Xcode to build it.\n\n```\n~/Library/Developer/Xcode/DerivedData/WebDriverAgent-<random string>/Build/Products/Debug-iphoneos/WebDriverAgentRunner-Runner.app\n```\n\nYou can then set your Appium capabilities as follows:\n\n```ruby\n# Ruby\ncapabilities: {\n \"platformName\": \"ios\",\n \"appium:automationName\": \"xcuitest\",\n \"appium:udid\": \"<udid>\",\n \"appium:usePreinstalledWDA\": true,\n \"appium:prebuiltWDAPath\": \"/path/to/Library/Developer/Xcode/DerivedData/WebDriverAgent-<random string>/Build/Products/Debug-iphoneos/WebDriverAgentRunner-Runner.app\"\n}\n@core = Appium::Core.for capabilities: capabilities\ndriver = @core.start_driver\n# do something\ndriver.quit\n```\n\n!!! note\n\n As of iOS 17, the testmanagerd service name has changed from `com.apple.testmanagerd` to\n `com.apple.dt.testmanagerd.runner`. It causes an unexpected WDA process crash with embedded\n XCTest frameworks while running a single WebDriverAgent package on various OS environments\n without `xcodebuild`.\n\n Since WDA v5.10.0, the module can refer to the device's local XCTest frameworks. It lets the\n Appium/WebDriverAgent package use proper dependencies for the device with a single prebuilt\n WebDriverAgent package. To set this up, you should remove the package internal frameworks from\n `WebDriverAgentRunner-Runner.app` with `rm -rf WebDriverAgentRunner-Runner.app/Frameworks/XC*.framework`.\n The WDA package itself is available from <https://github.com/appium/WebDriverAgent>.","metadata":{"headerPath":"## Set `appium:prebuiltWDAPath`","sectionCount":1,"filename":"run-preinstalled-wda.md","relativePath":"appium-xcuitest-driver/docs/guides/run-preinstalled-wda.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Touch ID\n---\n\nThe XCUITest driver has the capability to simulate [Touch ID](https://support.apple.com/en-ca/HT201371).\n\n!!! note\n\n This functionality is only supported on simulators.\n\n## Configuration\n\nTo use Touch ID, the application that Appium launches from (Terminal, iTerm, etc.) must be added to\nthe accessibility preferences on your Mac. Navigate to _System Preferences -> Privacy & Security ->\nAccessibility_ and under _Allow the apps below to control your computer_ add the application.\n\nWhy this is needed: The only way Appium can enable enrollment and toggling of Touch ID is to use\nsystem-level accessibility APIs to simulate mouse clicks on the simulator menus via AppleScript.\n\n## Usage\n\n* Set the capability `appium:allowTouchIdEnroll` to `true`.\n* When the Simulator starts, Touch ID enrollment will be enabled by default\n* You can toggle Touch ID enrollment by calling the\n [`mobile: enrollBiometric`](../reference/execute-methods.md#mobile-enrollbiometric) extension\n\n!!! note\n\n Remember that not all iOS devices have Touch ID, so your tests should handle cases where\n Touch ID is not supported.","metadata":{"headerPath":"","sectionCount":3,"filename":"touch-id.md","relativePath":"appium-xcuitest-driver/docs/guides/touch-id.md"}},{"pageContent":"---\ntitle: Troubleshooting\n---\n\n## Known Problems\n\n* Real devices with iOS/iPadOS 15+ show an overlay with the text `Automation Running Hold both\n volume buttons to stop` while WebDriverAgent is running. This is a known limitation of the XCTest\n framework. Note that screenshotting functionality is not affected (i.e. the overlay is not visible\n on taken screenshots).\n* Real devices with iOS/iPadOS 15+ [require passcode or Touch ID](https://github.com/appium/appium/issues/15898#issuecomment-927340411)\n when starting a new session. A workaround for this is to disable passcode/Touch ID on the device.\n* After many failures on a real device, it could transition to a state where connections are no\n longer being accepted. Rebooting the device can help remedy this problem. Please read\n [this issue](https://github.com/facebook/WebDriverAgent/issues/507) for more details.\n* `shake` is implemented via AppleScript and works only on Simulator due to lack of support from Apple","metadata":{"headerPath":"","sectionCount":2,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Interact with dialogs managed by `com.apple.springboard`\n\nSystem dialogs, such as permission dialogs, might not be interactable directly when the active application is not `com.apple.springboard`.\nDespite a similar look, dialogs belonging to the active session application (e.g. initially passed as `appium:app` or `appium:bundleId` capability value)\ndo not require such adjustment.\n\nXCUITest driver offers a couple of approaches to handle them:","metadata":{"headerPath":"## Interact with dialogs managed by `com.apple.springboard`","sectionCount":1,"recursiveSplit":true,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Interact with dialogs managed by `com.apple.springboard`\n\n- Set the [respectSystemAlerts setting](../reference/settings.md) to `true`. It enforces the active application\n detection algorithm to check a presence of system alerts and to return the Springboard app if this check succeeds.\n Such approach emulates the driver behavior prior to version 6 of XCUITest driver, although it might slightly\n slow down your scripts because each attempt to detect an active app would require to also query for alerts\n presence.\n- Start a session without `appium:app` nor `appium:bundleId`. Then XCUITest driver attempts to get the current active application. This requires you to start an application after a new session request with [`mobile: installApp`](../reference/execute-methods.md#mobile-installapp) to install an app if needed and [`mobile: launchApp`](../reference/execute-methods.md#mobile-launchapp)/[`mobile: activateApp`](../reference/execute-methods.md#mobile-activateapp), but it could automatically change the active application with `com.apple.springboard` or activate an application at the foreground. (Note that the automatic app detection might be lengthy, thus each action could take more time.)\n - When a permission alert exists at the foreground, it could select the `com.apple.springboard`\n - When another application is at the foreground by accepting/denying the system alert, or [`mobile: activateApp`](../reference/execute-methods.md#mobile-activateapp), the application would be selected as an active application.\n- [`mobile: alert`](../reference/execute-methods.md#mobile-alert)\n- `defaultActiveApplication` setting in [Settings](../reference/settings.md).\n - e.g. With the [Appium Ruby client](https://github.com/appium/ruby_lib_core)\n ```ruby\n # Interacting with the test target\n driver.settings.update({defaultActiveApplication: \"com.apple.springboard\"})\n # to accept the alert\n driver.find_element(\"accessibility_id\", \"Allow Once\").click\n driver.settings.update({defaultActiveApplication: \"auto\"})\n # keep interacting with the test target\n ```\n- Enable `appium:autoAcceptAlerts`/`appium:autoDismissAlerts`, or interact with alerts via [User Prompts](https://www.w3.org/TR/webdriver1/#user-prompts) in WebDriver endpoints\n - e.g. `driver.switch_to.alert.accept` with the [Appium Ruby client](https://github.com/appium/ruby_lib_core)","metadata":{"headerPath":"## Interact with dialogs managed by `com.apple.springboard`","sectionCount":1,"recursiveSplit":true,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Interact with dialogs managed by `com.apple.springboard`\n\n- e.g. `driver.switch_to.alert.accept` with the [Appium Ruby client](https://github.com/appium/ruby_lib_core)\n - It might be necessary to coordinate element selection via `acceptAlertButtonSelector`/`dismissAlertButtonSelector` settings in [Settings](../reference/settings.md)\n- Activate `com.apple.springboard` with [`mobile: activateApp`](../reference/execute-methods.md#mobile-activateapp) before interacting with dialogs","metadata":{"headerPath":"## Interact with dialogs managed by `com.apple.springboard`","sectionCount":1,"recursiveSplit":true,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Interact with dialogs managed by `com.apple.springboard`\n\n[`mobile: activeAppInfo`](../reference/execute-methods.md#mobile-activateappinfo) helps to understand what application (bundleId) is considered as active for the XCUITest driver.","metadata":{"headerPath":"## Interact with dialogs managed by `com.apple.springboard`","sectionCount":1,"recursiveSplit":true,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Interact with dialogs managed by `com.apple.ContactsUI.LimitedAccessPromptView`\n\niOS 18 introduced a new process named `com.apple.ContactsUI.LimitedAccessPromptView`. See [this issue](https://github.com/appium/appium/issues/20591) for more details.\nAs of XCUITest driver v7.26.4, the only workaround to interact with views available through the process is the below method:\n\n- `defaultActiveApplication` setting in [Settings](../reference/settings.md).\n - e.g. With the [Appium Ruby client](https://github.com/appium/ruby_lib_core)\n ```ruby\n # Interacting with the test target\n driver.settings.update({defaultActiveApplication: \"com.apple.ContactsUI.LimitedAccessPromptView\"})\n # to accept the alert\n driver.find_element(\"accessibility_id\", \"Select Contacts\").click\n driver.settings.update({defaultActiveApplication: \"auto\"})\n # keep interacting with the test target\n ```\n\nThe `com.apple.ContactsUI.LimitedAccessPromptView` process can get elements available through `com.apple.springboard`, such as several system permission dialogs.\niOS 18+ devices may be possible to use `com.apple.ContactsUI.LimitedAccessPromptView` to interact with elements managed either by `com.apple.ContactsUI.LimitedAccessPromptView` or `com.apple.springboard`.","metadata":{"headerPath":"## Interact with dialogs managed by `com.apple.ContactsUI.LimitedAccessPromptView`","sectionCount":1,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Leftover Application Data on Real Devices\n\nThere might be a situation where application data is present on the real device, even if the\napplication itself is not installed. This could happen if:\n\n- The app is in an [offloaded state](https://discussions.apple.com/thread/254887240)\n- The application state is cached\n- There was an unexpected failure while installing the app. An example of such failure is the\n `ApplicationVerificationFailed` which happens while installing an app signed with an invalid provisioning profile.\n\nIn the above cases, the application identifier will not be listed in the output of\n[`mobile: listApps`](../reference/execute-methods.md#mobile-listapps), and it will not be detected\nby [`mobile: isAppInstalled`](../reference/execute-methods.md#mobile-isappinstalled). Setting\n`appium:fullReset` or `appium:enforceAppInstall` capabilities to `true` also will not help clear this data.\n\nThe only way to completely get rid of the cached application data is to call the\n[`mobile: removeApp`](../reference/execute-methods.md#mobile-removeapp) command with the appropriate\nbundle identifier.\n\nThe driver does automatically try to resolve application installs that failed because of the\n`MismatchedApplicationIdentifierEntitlement` error. However, in cases when the previously installed\napplication's provisioning profile is different from what currently the driver is trying to\ninstall, and if you explicitly set the driver to _not_ perform application uninstall, then consider\ncalling [`mobile: removeApp`](../reference/execute-methods.md#mobile-removeapp) before the\n`MismatchedApplicationIdentifierEntitlement` error occurs. Example steps can be as follows:\n\n1. Start a session without `appium:app` and `appium:bundleId` capabilities\n2. Call [`mobile: removeApp`](../reference/execute-methods.md#mobile-removeapp) for the target\n application's bundle id\n3. Install the test target with [`mobile: installApp`](../reference/execute-methods.md#mobile-installapp)\n4. Launch the application with [`mobile: launchApp`](../reference/execute-methods.md#mobile-launchapp)\n or [`mobile: activateApp`](../reference/execute-methods.md#mobile-activateapp)\n\n\n!!! note\n\n We observed that iOS 18+ environments can retain the permission preference even after reinstallation.\n Please refer to [this issue](https://github.com/appium/appium-xcuitest-driver/issues/2572) for more information about this behavior.\n\n## Weird State","metadata":{"headerPath":"## Leftover Application Data on Real Devices","sectionCount":2,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Weird State > ### Real Device Stops Responding\n\nRunning tests on a real device is particularly flakey. If things stop responding, the only recourse\nis, most often, to restart the device. Logs in the form of the following _may_ start to occur:\n\n```shell\ninfo JSONWP Proxy Proxying [POST /session] to [POST http://10.35.4.122:8100/session] with body: {\"desiredCapabilities\":{\"ap...\"\ndbug WebDriverAgent Device: Jul 26 13:20:42 iamPhone XCTRunner[240] <Warning>: Listening on USB\ndbug WebDriverAgent Device: Jul 26 13:21:42 iamPhone XCTRunner[240] <Warning>: Enqueue Failure: UI Testing Failure - Unable to update application state promptly. <unknown> 0 1\ndbug WebDriverAgent Device: Jul 26 13:21:57 iamPhone XCTRunner[240] <Warning>: Enqueue Failure: UI Testing Failure - Failed to get screenshot within 15s <unknown> 0 1\ndbug WebDriverAgent Device: Jul 26 13:22:57 iamPhone XCTRunner[240] <Warning>: Enqueue Failure: UI Testing Failure - App state of (null) is still unknown <unknown> 0 1\n```\n\n## Weird State > ### Command Takes 60+ Seconds\n\nSometimes it is possible to encounter slowdowns for an additional 60 seconds for a command that\nusually should not take long. This may be caused by a crash in the `testmanagerd` process on the\ndevice under test. In such a case, the OS tries to restore the process, then wait for the resurrected\ndaemon to connect to the target process, which causes the aforementioned delay.\n\nThis can be fixed by terminating the target application process. For example, if this behavior\noccurs while calling `mobile: queryAppState`, you can terminate the application once, or restart the\ndevice entirely. Please check [this pull request](https://github.com/appium/WebDriverAgent/pull/774)\nfor more details.","metadata":{"headerPath":"## Weird State > ### Real Device Stops Responding","sectionCount":2,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Real Device Security Settings\n\nOn some systems, especially CI ones, where tests are executed by command line agents, macOS\nAccessibility restrictions result in the WebDriverAgent process being unable to retrieve the\ndevelopment keys from the system keychain. This usually manifests by `xcodebuild` returning error\ncode `65`. One workaround for this is to use a private key that is not stored on the system\nkeychain. See [this issue](https://github.com/appium/appium/issues/6955) and\n[this Stack Exchange post](http://stackoverflow.com/questions/16550594/jenkins-xcode-build-works-codesign-fails).\n\nTo export the key, use\n\n```\nsecurity create-keychain -p [keychain_password] MyKeychain.keychain\nsecurity import MyPrivateKey.p12 -t agg -k MyKeychain.keychain -P [p12_Password] -A\n```\n\nwhere `MyPrivateKey.p12` is the private development key exported from the system keychain.\n\nYou can then use the [`appium:keychainPath`](../reference/capabilities.md#webdriveragent) and\n[`appium:keychainPassword`](../reference/capabilities.md#webdriveragent) capabilities to pass this\nkeychain to WebDriverAgent.\n\n## Simulator Resetting\n\nWhen testing on simulators, the driver tries to leave the simulator state as it found it:\n\n* If no `udid` is provided, the driver will create a new iOS simulator, run tests on it, and then\n delete the simulator\n* If a specific `udid` is provided for a simulator that _is not_ running, the driver will boot the\n specified simulator, run tests on it, and then shut the simulator down\n* If a specific `udid` is provided for a simulator that _is_ running, the driver will connect to the\n existing simulator, run tests, and then leave the simulator running\n\nYou can use the `appium:noReset` capability to adjust this behavior: setting it to `true` will\nleave the simulator running at the end of a test session.\n\n## Caching Issues During Build\n\nTesting on iOS generates files that can sometimes get large. These include logs, temporary files,\nand derived data from Xcode runs, all of which are safe to delete if any issues arise. The files are\nusually found in the following locations, should they need to be deleted:\n\n```\n$HOME/Library/Logs/CoreSimulator/*\n$HOME/Library/Developer/Xcode/DerivedData/*\n```","metadata":{"headerPath":"## Real Device Security Settings","sectionCount":3,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"## Frequent `Disconnecting from remote debugger` error in iOS 17\n\nPlease try out iOS 17.6 or a newer version which includes [a possible fix by Apple](https://developer.apple.com/documentation/safari-release-notes/safari-17_6-release-notes#Web-Inspector).\n\nFrequent Web Inspector debugger disconnection started since iOS 17.2 (or iOS 17.0), that eventually caused `Disconnecting from remote debugger` error.\nIt could be improved since iOS 17.6.\nPlease check [the corresponding pull request](https://github.com/appium/appium-xcuitest-driver/pull/2334) for more details.","metadata":{"headerPath":"## Frequent `Disconnecting from remote debugger` error in iOS 17","sectionCount":1,"filename":"troubleshooting.md","relativePath":"appium-xcuitest-driver/docs/guides/troubleshooting.md"}},{"pageContent":"---\ntitle: tvOS Support\n---\n\nThe XCUITest driver supports automation of the tvOS platform.\n\n<img src=\"https://user-images.githubusercontent.com/5511591/55161297-876e0200-51a8-11e9-8313-8d9f15a0db9d.gif\" width=50%>\n\n!!! warning\n\n Support for network-only Apple TV devices is limited.\n This is because [`appium-ios-device`](https://github.com/appium/appium-ios-device),\n which handles low-level communication with devices, only supports USB-connected devices.\n\n## Setup\n\nYou can run tests for tvOS by setting the `platformName` capability to `tvOS`:\n\n```json\n{\n \"platformName\": \"tvOS\", // here\n \"appium:automationName\": \"XCUITest\",\n \"appium:platformVersion\": \"12.2\",\n \"appium:deviceName\": \"Apple TV\",\n ...\n}\n```\n\n!!! note\n\n If using a simulator, make sure the tvOS simulator exists in your simulator list. You can run\n `xcrun simctl list | grep \"com.apple.CoreSimulator.SimRuntime.tvOS\"` to verify this.\n\n## Setup > ### Network-Only Real Devices\n\nTo run tests on network-only Apple TV devices, you may need the following:\n\n- Xcode 26.1 or later (to execute `xcodebuild` against such network-only Apple TV devices)\n- Set the `APPIUM_XCUITEST_PREFER_DEVICECTL` environment variable\n- Provide the `appium:wdaBaseUrl` capability; it must be `http://<the Apple TV's IP address>`\n\n!!! note\n\n If you provide `appium:webDriverAgentUrl` to manage WebDriverAgent process by yourself,\n only `APPIUM_XCUITEST_PREFER_DEVICECTL` might be sufficient.\n\n If your environment exposes the `usbmuxd` interface to Appium via third-party tools,\n `APPIUM_XCUITEST_PREFER_DEVICECTL` may not be needed.\n This environment variable could cause conflicts in several behaviors.","metadata":{"headerPath":"","sectionCount":3,"filename":"tvos.md","relativePath":"appium-xcuitest-driver/docs/guides/tvos.md"}},{"pageContent":"## Basic Actions\n\ntvOS provides [remote controller](https://developer.apple.com/design/human-interface-guidelines/tvos/remote-and-controllers/remote/)\nbased actions. The XCUITest driver implements these actions using the\n[`mobile: pressButton`](../reference/execute-methods.md#mobile-pressbutton) extension, with the\nfollowing button values: `menu`, `up/down/left/right`, `home`, `playpause` and `select`.\n\nAll actions are performed on the _focused_ element (which has the `focus` attribute set). The\nfocused element is automatically changed after using `mobile: pressButton`.\n\nIt is also possible to use the standard `findElement` and `click` methods. The XCUITest driver will\nautomatically calculate the necessary sequence of `up/down/left/right` and `select` button presses,\nso you should not care about which keys should be pressed to reach an arbitrary element every time.\n\n=== \"Java\"\n\n ```java\n WebElement element = driver.findElementByAccessibilityId(\"element on the app\");\n element.getAttribute(\"focused\"); // => 'true'\n // Appium moves the focus to the element by pressing the corresponding keys and clicking the element\n element.click();\n driver.queryAppState(\"test.package.name\"); // => :running_in_foreground\n driver.executeScript(\"mobile: pressButton\", ImmutableMap.of(\"name\", \"Home\"));\n driver.executeScript(\"mobile: pressButton\", ImmutableMap.of(\"name\", \"Up\"));\n element = driver.switchTo().activeElement();\n element.getAttribute(\"label\");\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```javascript\n const element = $('~SomeAccessibilityId');\n element.getAttribute('focused');\n element.click();\n driver.execute('mobile: pressButton', {name: 'Home'});\n driver.execute('mobile: pressButton', {name: 'Up'});\n const activeElement = driver.getActiveElement();\n activeElement.getAttribute('label');\n ```\n\n=== \"Python\"\n\n ```Python\n element = driver.find_element_by_accessibility_id('element on the app')\n element.get_attribute('focused')\n element.click()\n driver.query_app_state('test.package.name')\n driver.execute_script('mobile: pressButton', { 'name': 'Home' })\n driver.execute_script('mobile: pressButton', { 'name': 'Up' })\n element = driver.switch_to.active_element\n element.get_attribute('label')\n ```\n\n=== \"Ruby\"","metadata":{"headerPath":"## Basic Actions","sectionCount":1,"recursiveSplit":true,"filename":"tvos.md","relativePath":"appium-xcuitest-driver/docs/guides/tvos.md"}},{"pageContent":"## Basic Actions\n\n=== \"Ruby\"\n\n ```ruby\n element = @driver.find_element :accessibility_id, 'element on the app'\n element.focused\n element.click\n @driver.app_state('test.package.name')\n @driver.execute_script 'mobile: pressButton', { name: 'Home' }\n @driver.execute_script 'mobile: pressButton', { name: 'Up' }\n element = @driver.switch_to.active_element\n element.label\n ```","metadata":{"headerPath":"## Basic Actions","sectionCount":1,"recursiveSplit":true,"filename":"tvos.md","relativePath":"appium-xcuitest-driver/docs/guides/tvos.md"}},{"pageContent":"## More Actions\n\n* Consider using `wait` methods, since tvOS also has animation\n* The `menu` button works as _back_ for iOS context in tvOS\n\n## Known Limitations\n\n* Gesture commands do not work for tvOS. Some commands such as pasteboard do not work as well.\n\n## Related Tickets\n\n* <https://github.com/appium/appium/pull/12401>\n* <https://github.com/appium/appium-xcuitest-driver/pull/911>\n* <https://github.com/appium/appium-xcuitest-driver/pull/931>\n* <https://github.com/appium/appium-xcuitest-driver/pull/939>\n* <https://github.com/appium/WebDriverAgent/pull/163>\n* <https://github.com/appium/appium-xcuitest-driver/pull/2194>","metadata":{"headerPath":"## More Actions","sectionCount":3,"filename":"tvos.md","relativePath":"appium-xcuitest-driver/docs/guides/tvos.md"}},{"pageContent":"---\ntitle: Manage WebDriverAgent by Yourself\n---\n\nThe XCUITest driver uses [WebDriverAgent](https://github.com/appium/WebDriverAgent) (WDA) as the\nautomation backend. This backend is based on Apple's XCTest framework and shares all the known\nproblems that are present in XCTest. For some of them we have workarounds, but there are some that\nare hardly possible to workaround ([here is one example](https://github.com/facebookarchive/WebDriverAgent/issues/507)).\nThe approach described in this article enables you to have full control over how WDA is built,\nmanaged, and run on the device. This way you may fine-tune your automated tests in a CI environment\nand make them more stable inlong-running perspective.\n\n!!! note\n\n * The steps below are not necessary if default Appium capabilities are used. The server will do\n everything for you, however, you will not have so much control over WDA.\n * It is mandatory to have SSH or physical access to the machine to which the device under test\n is connected.\n\n### WDA Setup\n\nIn order to setup and launch WDA, please check the provided steps in the\n[Run Preinstalled WDA](./run-preinstalled-wda.md#using-xcode) documentation.","metadata":{"headerPath":"","sectionCount":2,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"### WDA Startup via Code\n\nWebDriverAgent application acts as a REST server, which proxies external API requests to native\nXCTest calls for your application under test. The server address will be `localhost` if you run your\ntests on a simulator, or the actual phone IP address in case of real device. Appium uses\n[`appium-ios-device`](https://github.com/appium/appium-ios-device) to route network requests to a\nreal device from `localhost` via USB, which means one can use this tool to unify the WDA network\naddresses for a simulator and real device.\n\nYou can use `appium-ios-device` to connect to a remote device by requiring the module from your\nJavaScript code. Alternatively, you can use [`iproxy`](https://github.com/libimobiledevice/libusbmuxd#iproxy),\n[`go-ios`](https://github.com/danielpaulus/go-ios) or [`tidevice`](https://github.com/alibaba/taobao-iphone-device)\nto handle the WDA process outside Appium, by installing and launching the WDA package. For instance,\n`iproxy` can be installed using `npm`: `npm install -g iproxy`.\n\nThis helper class written in Java illustrates the main implementation details with `iproxy`:\n\n```java\npublic class WDAServer {\n private static final Logger log = ZLogger.getLog(WDAServer.class.getSimpleName());\n\n private static final int MAX_REAL_DEVICE_RESTART_RETRIES = 1;\n private static final Timedelta REAL_DEVICE_RUNNING_TIMEOUT = Timedelta.ofMinutes(4);\n private static final Timedelta RESTART_TIMEOUT = Timedelta.ofMinutes(1);\n\n // These settings are needed to properly sign WDA for real device tests\n // See https://github.com/appium/appium-xcuitest-driver for more details\n private static final File KEYCHAIN = new File(String.format(\"%s/%s\",\n System.getProperty(\"user.home\"), \"/Library/Keychains/MyKeychain.keychain\"));\n private static final String KEYCHAIN_PASSWORD = \"******\";","metadata":{"headerPath":"### WDA Startup via Code","sectionCount":1,"recursiveSplit":true,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"### WDA Startup via Code\n\nprivate static final File IPROXY_EXECUTABLE = new File(\"/usr/local/bin/iproxy\");\n private static final File XCODEBUILD_EXECUTABLE = new File(\"/usr/bin/xcodebuild\");\n private static final File WDA_PROJECT =\n new File(\"~/.appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent\" +\n \"/WebDriverAgent.xcodeproj\");\n private static final String WDA_SCHEME = \"WebDriverAgentRunner\";\n private static final String WDA_CONFIGURATION = \"Debug\";\n private static final File XCODEBUILD_LOG = new File(\"/usr/local/var/log/appium/build.log\");\n private static final File IPROXY_LOG = new File(\"/usr/local/var/log/appium/iproxy.log\");\n\n private static final int PORT = 8100;\n public static final String SERVER_URL = String.format(\"http://127.0.0.1:%d\", PORT);\n\n private static final String[] IPROXY_CMDLINE = new String[]{\n IPROXY_EXECUTABLE.getAbsolutePath(),\n Integer.toString(PORT),\n Integer.toString(PORT),\n String.format(\"> %s 2>&1 &\", IPROXY_LOG.getAbsolutePath())\n };\n\n private static WDAServer instance = null;\n private final boolean isRealDevice;\n private final String deviceId;\n private final String platformVersion;\n private int failedRestartRetriesCount = 0;\n\n private WDAServer() {\n try {\n this.isRealDevice = !getIsSimulatorFromConfig(getClass());\n final String udid;\n if (isRealDevice) {\n udid = IOSRealDeviceHelpers.getUDID();\n } else {\n udid = IOSSimulatorHelpers.getId();\n }\n this.deviceId = udid;\n this.platformVersion = getPlatformVersionFromConfig(getClass());\n } catch (Exception e) {\n throw new RuntimeException(e);\n }\n ensureToolsExistence();\n ensureParentDirExistence();\n }\n\n public synchronized static WDAServer getInstance() {\n if (instance == null) {\n instance = new WDAServer();\n }\n return instance;\n }","metadata":{"headerPath":"### WDA Startup via Code","sectionCount":1,"recursiveSplit":true,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"### WDA Startup via Code\n\npublic synchronized static WDAServer getInstance() {\n if (instance == null) {\n instance = new WDAServer();\n }\n return instance;\n }\n\n private boolean waitUntilIsRunning(Timedelta timeout) throws Exception {\n final URL status = new URL(SERVER_URL + \"/status\");\n try {\n if (timeout.asSeconds() > 5) {\n log.debug(String.format(\"Waiting max %s until WDA server starts responding...\", timeout));\n }\n new UrlChecker().waitUntilAvailable(timeout.asMillis(), TimeUnit.MILLISECONDS, status);\n return true;\n } catch (UrlChecker.TimeoutException e) {\n return false;\n }\n }\n\n private static void ensureParentDirExistence() {\n if (!XCODEBUILD_LOG.getParentFile().exists()) {\n if (!XCODEBUILD_LOG.getParentFile().mkdirs()) {\n throw new IllegalStateException(String.format(\n \"The script has failed to create '%s' folder for Appium logs. \" +\n \"Please make sure your account has correct access permissions on the parent folder(s)\",\n XCODEBUILD_LOG.getParentFile().getAbsolutePath()));\n }\n }\n }\n\n private void ensureToolsExistence() {\n if (isRealDevice && !IPROXY_EXECUTABLE.exists()) {\n throw new IllegalStateException(String.format(\"%s tool is expected to be installed (`npm install -g iproxy`)\",\n IPROXY_EXECUTABLE.getAbsolutePath()));\n }\n if (!XCODEBUILD_EXECUTABLE.exists()) {\n throw new IllegalStateException(String.format(\"xcodebuild tool is not detected on the current system at %s\",\n XCODEBUILD_EXECUTABLE.getAbsolutePath()));\n }\n if (!WDA_PROJECT.exists()) {\n throw new IllegalStateException(String.format(\"WDA project is expected to exist at %s\",\n WDA_PROJECT.getAbsolutePath()));\n }\n }","metadata":{"headerPath":"### WDA Startup via Code","sectionCount":1,"recursiveSplit":true,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"### WDA Startup via Code\n\nprivate List<String> generateXcodebuildCmdline() {\n final List<String> result = new ArrayList<>();\n result.add(XCODEBUILD_EXECUTABLE.getAbsolutePath());\n result.add(\"clean build-for-testing test-without-building\");\n result.add(String.format(\"-project %s\", WDA_PROJECT.getAbsolutePath()));\n result.add(String.format(\"-scheme %s\", WDA_SCHEME));\n result.add(String.format(\"-destination id=%s\", deviceId));\n result.add(String.format(\"-configuration %s\", WDA_CONFIGURATION));\n result.add(String.format(\"IPHONEOS_DEPLOYMENT_TARGET=%s\", platformVersion));\n result.add(String.format(\"> %s 2>&1 &\", XCODEBUILD_LOG.getAbsolutePath()));\n return result;\n }\n\n private static List<String> generateKeychainUnlockCmdlines() throws Exception {\n final List<String> result = new ArrayList<>();\n result.add(String.format(\"/usr/bin/security -v list-keychains -s %s\", KEYCHAIN.getAbsolutePath()));\n result.add(String.format(\"/usr/bin/security -v unlock-keychain -p %s %s\",\n KEYCHAIN_PASSWORD, KEYCHAIN.getAbsolutePath()));\n result.add(String.format(\"/usr/bin/security set-keychain-settings -t 3600 %s\", KEYCHAIN.getAbsolutePath()));\n return result;\n }\n\n public synchronized void restart() throws Exception {\n if (isRealDevice && failedRestartRetriesCount >= MAX_REAL_DEVICE_RESTART_RETRIES) {\n throw new IllegalStateException(String.format(\n \"WDA server cannot start on the connected device with udid %s after %s retries. \" +\n \"Reboot the device manually and try again\", deviceId, MAX_REAL_DEVICE_RESTART_RETRIES));\n }\n\n final String hostname = InetAddress.getLocalHost().getHostName();\n log.info(String.format(\"Trying to (re)start WDA server on %s:%s...\", hostname, PORT));\n UnixProcessHelpers.killProcessesGracefully(IPROXY_EXECUTABLE.getName(), XCODEBUILD_EXECUTABLE.getName());","metadata":{"headerPath":"### WDA Startup via Code","sectionCount":1,"recursiveSplit":true,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"### WDA Startup via Code\n\nfinal File scriptFile = File.createTempFile(\"script\", \".sh\");\n try {\n final List<String> scriptContent = new ArrayList<>();\n scriptContent.add(\"#!/bin/bash\");\n if (isRealDevice && isRunningInJenkinsNetwork()) {\n scriptContent.add(String.join(\"\\n\", generateKeychainUnlockCmdlines()));\n }\n if (isRealDevice) {\n scriptContent.add(String.join(\" \", IPROXY_CMDLINE));\n }\n final String wdaBuildCmdline = String.join(\" \", generateXcodebuildCmdline());\n log.debug(String.format(\"Building WDA with command line:\\n%s\\n\", wdaBuildCmdline));\n scriptContent.add(wdaBuildCmdline);\n try (Writer output = new BufferedWriter(new FileWriter(scriptFile))) {\n output.write(String.join(\"\\n\", scriptContent));\n }\n new ProcessBuilder(\"/bin/chmod\", \"u+x\", scriptFile.getCanonicalPath())\n .redirectErrorStream(true).start().waitFor(5, TimeUnit.SECONDS);\n final ProcessBuilder pb = new ProcessBuilder(\"/bin/bash\", scriptFile.getCanonicalPath());\n final Map<String, String> env = pb.environment();\n // This is needed for Jenkins\n env.put(\"BUILD_ID\", \"dontKillMe\");\n // This line is important. If USE_PORT environment variable is not set then WDA\n // takes port number zero by default and won't accept any incoming requests\n env.put(\"USE_PORT\", Integer.toString(PORT));\n log.info(String.format(\"Waiting max %s for WDA to be (re)started on %s:%s...\", RESTART_TIMEOUT.toString(),\n hostname, PORT));\n final Timedelta started = Timedelta.now();\n pb.redirectErrorStream(true).start().waitFor(RESTART_TIMEOUT.asMillis(), TimeUnit.MILLISECONDS);\n if (!waitUntilIsRunning(RESTART_TIMEOUT)) {\n ++failedRestartRetriesCount;\n throw new IllegalStateException(\n String.format(\"WDA server has failed to start after %s timeout on server '%s'.\\n\"\n + \"Please make sure that iDevice is properly connected and you can build \"\n + \"WDA manually from XCode.\\n\"\n + \"Xcodebuild logs:\\n\\n%s\\n\\n\\niproxy logs:\\n\\n%s\\n\\n\\n\",\n RESTART_TIMEOUT, hostname,","metadata":{"headerPath":"### WDA Startup via Code","sectionCount":1,"recursiveSplit":true,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"### WDA Startup via Code\n\n+ \"Xcodebuild logs:\\n\\n%s\\n\\n\\niproxy logs:\\n\\n%s\\n\\n\\n\",\n RESTART_TIMEOUT, hostname,\n getLog(XCODEBUILD_LOG).orElse(\"EMPTY\"), getLog(IPROXY_LOG).orElse(\"EMPTY\"))\n );\n }","metadata":{"headerPath":"### WDA Startup via Code","sectionCount":1,"recursiveSplit":true,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"### WDA Startup via Code\n\nlog.info(String.format(\"WDA server has been successfully (re)started after %s \" +\n \"and now is listening on %s:%s\", Timedelta.now().diff(started).toString(), hostname, PORT));\n } finally {\n scriptFile.delete();\n }\n }\n\n public boolean isRunning() throws Exception {\n if (!isProcessRunning(XCODEBUILD_EXECUTABLE.getName())\n || (isRealDevice && !isProcessRunning(IPROXY_EXECUTABLE.getName()))) {\n return false;\n }\n return waitUntilIsRunning(isRealDevice ? REAL_DEVICE_RUNNING_TIMEOUT : Timedelta.ofSeconds(3));\n }\n\n public Optional<String> getLog(File logFile) {\n if (logFile.exists()) {\n try {\n return Optional.of(new String(Files.readAllBytes(logFile.toPath()), Charset.forName(\"UTF-8\")));\n } catch (IOException e) {\n e.printStackTrace();\n }\n }\n return Optional.empty();\n }\n}\n```\n\nThe following piece of code should then be called before starting the XCUITest driver:\n\n```java\nif (!WDAServer.getInstance().isRunning()) {\n WDAServer.getInstance().restart();\n}\n```\n\nIt is important to set the `appium:webDriverAgentUrl` capability for the driver to let it know\nthat WDA is ready for use:\n\n```java\ncapabilities.setCapability(\"webDriverAgentUrl\", WDAServer.SERVER_URL);\n```","metadata":{"headerPath":"### WDA Startup via Code","sectionCount":1,"recursiveSplit":true,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"### Important Notes\n\n* The process does not have direct access to keychain if it is executed by a continuous integration\n agent, so the keychain must be prepared before compiling WDA for real device, otherwise\n codesigning will fail. Check the [CI Setup](./ci-setup.md) documentation for details.\n* The `xcodebuild` and `iproxy` processes are killed before restart to make sure compilation\n succeeds, in case the processes are frozen\n* A dedicated `bash` script is used to detach the `iproxy`/`xcodebuild` processes, so they can\n continue running in background even after the actual code execution is finished. This is extremely\n important if multiple tests/suites are executed on the same machine/node in automation lab, which\n requires minimum human interaction\n* The value of the `BUILD_ID` environment variable is changed to avoid the CI agent killing the\n background process after the job is finished\n* The `isRunning` check is done by verifying the actual network endpoint\n* The output of daemonized processes is logged, so it is possible to track errors and unexpected\n failures. The content of the log files is automatically added to the actual error message if the\n server fails to (re)start.\n* Real device id can be parsed from `system_profiler SPUSBDataType` output\n* Simulator id can be parsed from `xcrun simctl list` output\n* The `UrlChecker` class is imported from the `org.openqa.selenium.net` package","metadata":{"headerPath":"### Important Notes","sectionCount":1,"filename":"wda-custom-server.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-custom-server.md"}},{"pageContent":"---\ntitle: Diagnosing WebDriverAgent Slowness\n---\n\nThe XCUITest driver is based on Apple's [XCTest](https://developer.apple.com/documentation/xctest)\ntest automation framework and thus inherits most (if not all) properties and features this framework\nprovides. The purpose of this article is to help with optimization of automation scenarios that\ndon't perform well and/or to explain possible causes of such behavior.\n\n## \"Slowness\" could be different\n\nFirst, it is important to figure out what exactly is slow.\nThe Appium ecosystem is complicated and\nconsists of multiple layers, where each layer could influence the overall duration.\nFor example, when an API call is invoked from a client script, it must go through the following stages:\n\nYour automation script (Java, Python, C#, etc; runs on your machine)\n--> Appium Client Lib (Java, Python, C#, etc; runs on your machine)\n--> Appium Server (Node.js HTTP server; runs on your machine or a remote one)\n--> XCUITest Driver and/or Plugin (Node.js HTTP handler; runs on your machine or a remote one)\n--> WDA Server (ObjectiveC HTTP Server; runs on the remote mobile device)\n\nThe example above is the simplest flow. If you run your scripts using cloud providers\ninfrastructure then the amount of intermediate components in this chain may be much greater.\nLike it was mentioned above, it is very important to know on which stage(s)\n(or between them) the bottleneck is observed.\n\nThis particular article focuses only on the last stage: the WDA Server one.","metadata":{"headerPath":"","sectionCount":2,"filename":"wda-slowness.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-slowness.md"}},{"pageContent":"## WebDriverAgent (WDA) Server\n\nWDA source code is located in the separate [repository](https://github.com/appium/WebDriverAgent/tree/master).\nThe content of this repository is published as [appium-webdriveragent](https://www.npmjs.com/package/appium-webdriveragent)\nNPM package and contains several helper Node.js modules along with the WDA source code itself.\nThis source code is compiled into an .xctrunner bundle, which is a special application type\nthat contains tests (also it has some higher privileges in comparison to vanilla apps).\nWebDriverAgent project itself consists of three main parts:\n\n- Vendor Libs\n- WebDriverAgentLib\n- WebDriverAgentRunner\n\nVendor libs, like RoutingHTTPServer, ensure the support for low-level HTTP- and TCP-server APIs.\nWebDriverAgentLib defines handlers for [W3C WebDriver](https://www.w3.org/TR/webdriver/) endpoints\nand implements all the heavy-lifting procedures related to Apple's XCTest communication\nand some more custom stuff specific for the XCUITest driver.\nWebDriverAgentRunner is actually one long test, whose main purpose\nis to run the HTTP server implemented by the WebDriverAgentLib.\n\nImportant conclusions from the above information:\n\n- WDA is an HTTP server, which executes API commands by invoking HTTP response handlers\n- WDA uses Apple's XCTest APIs with various custom additions\n\n## How to confirm my script's bottleneck is WDA\n\nCheck the server logs in order to verify how long it takes for the XCUITest driver to receive a\nresponse from WDA. The log line that is written before an HTTP request is proxied to WDA looks\nlike `Proxying [X] to [Y]`. Also consider enabling server timestamps by providing the\n`--log-timestamp` command line parameter. If you observe timestamps between the above log line and the\nnext one differ too much and the difference is an anomaly (e.g. the same step is (much) faster\nfor other apps/environments/parameter combinations) then it might serve as a confirmation of a\nsuspicious slowness.\n\n## Patterns lookup\n\nAfter the slowness is confirmed it is important to determine behavior patterns, e.g. under which\ncircumstances does it happen, if it is always reproducible, etc. This article only targets specific\npatterns that the author knows of or dealt with. If your pattern is not present here then try to\nlook for possible occurrences in existing [issues](https://github.com/appium/appium/issues),\n[Appium forum](https://discuss.appium.io) or just search the internet.\n\n## Pattern: Application startup is slow","metadata":{"headerPath":"## WebDriverAgent (WDA) Server","sectionCount":4,"filename":"wda-slowness.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-slowness.md"}},{"pageContent":"## Pattern: Application startup is slow > ### Symptoms\n\nYou observe timeouts or unusual slowness (in comparison to manual execution performance)\nof the application startup on session init (if it also includes app startup)\nor mid-session app startup.\n\n## Pattern: Application startup is slow > ### Causes\n\nWhen XCTest starts an app it ensures the accessibility layer of it is ready for interactions.\nTo check that the framework verifies the application is idling (e.g. does not perform any actions\non the main thread) as well as all animations have been finished. If this check times out\nan exception is thrown or WDA may try to continue without any guarantees the app could be\ninteracted with (a.k.a. best effort strategy).\n\n## Pattern: Application startup is slow > ### Solutions\n\nI was observing applications that were constantly running something on the main thread in an endless loop.\nMost likely such apps are not automatable at all or hardly automatable without fixing the app\nsource code itself.\nYou may still try to tune the following capabilities and settings to influence the above timeout:\n\n- [appium:waitForIdleTimeout](../reference/capabilities.md)\n- [waitForIdleTimeout](../reference/settings.md)\n- [animationCoolOffTimeout](../reference/settings.md)\n\n## Pattern: Element location with XPath is slow\n\n## Pattern: Element location with XPath is slow > ### Symptoms\n\nYou observe timeouts or unusual slowness (in comparison to other location strategies)\nof XPath locators.\n\n## Pattern: Element location with XPath is slow > ### Causes\n\nThe [XPath](../reference/locator-strategies.md) location strategy\nis not natively supported by XCTest. It's a custom addition\nwhich is only available in WDA. Such locators have more features than others, but the price\nfor it is the observed slowness as we cannot rely on native XCTest location APIs\nwhile looking for elements using XPath.\nIn order to perform XPath lookup WDA needs to take a snapshot of the whole accessibility\nhierarchy with all element attributes resolved, which is a time-expensive operation.\nLocation slowness might be observed if:\n- The current app hierarchy is too large (e.g. has hundreds of elements). This is a known\n XCTest limitation.\n- The app is not idling/has active animations\n- It takes too long to determine each element's `visible` or `accessible` attributes, which are custom\n ones and are not present in the original XCTest implementation","metadata":{"headerPath":"## Pattern: Application startup is slow > ### Symptoms","sectionCount":6,"filename":"wda-slowness.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-slowness.md"}},{"pageContent":"## Pattern: Element location with XPath is slow > ### Solutions\n\nDepending on the actual cause there might be different applicable solutions. In general, the common\nadvice would be to avoid XPath locators where possible and use locators that are natively\nsupported by XCTest (like predicates or ids) and have better speed ranking.\nIf the usage of an XPath locators is a single available option then you may try to apply the following\nsuggestions:\n- Reduce the size of the app hierarchy using the [snapshotMaxDepth setting](../reference/settings.md).\n This might not help if the destination element is deeply nested -\n it won't be found if the value of this setting is lower than its nesting level.\n- Exclude the `visible` and/or `accessible` attributes from your query. These are\n custom attributes exclusive to WDA and their calculation is expensive in comparison\n to other native attributes.\n- Reduce various timeouts similarly to how it's advised in the\n [Application startup is slow](#pattern-application-startup-is-slow) pattern\n- Fix the source code of the application under test to reduce the amount of accessible elements\n on a single screen\n- Fix the source code of the application under test to avoid running long operations\n or animations on the main thread\n\n## Pattern: Element location with non-XPath is slow\n\n## Pattern: Element location with non-XPath is slow > ### Symptoms\n\nYou observe timeouts or unusual slowness with various non-XPath locators.\n\n## Pattern: Element location with non-XPath is slow > ### Causes\n\nLocation slowness might be observed if:\n- The current app hierarchy is too large (e.g. has hundreds of elements). This is a known\n XCTest limitation.\n- The app is not idling/has active animations\n- It takes too long to determine each element's `visible` or `accessible` attributes, which are custom\n ones and are not present in the original XCTest implementation (only applicable to predicate and class chain locators)","metadata":{"headerPath":"## Pattern: Element location with XPath is slow > ### Solutions","sectionCount":4,"filename":"wda-slowness.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-slowness.md"}},{"pageContent":"## Pattern: Element location with non-XPath is slow > ### Solutions\n\n- Reduce the size of the app hierarchy using the [snapshotMaxDepth setting](../reference/settings.md).\n This might not help if the destination element is deeply nested -\n it won't be found if the value of this setting is lower than its nesting level.\n- Exclude the `visible` and/or `accessible` attributes from your query\n (only applicable to predicate and class chain locators). These are\n custom attributes exclusive to WDA and their calculation is expensive in comparison\n to other native attributes.\n- Reduce various timeouts similarly to how it's advised in the\n [Application startup is slow](#pattern-application-startup-is-slow) pattern\n- Fix the source code of the application under test to reduce the amount of accessible elements\n on a single screen\n- Fix the source code of the application under test to avoid running long operations\n or animations on the main thread\n\n## Pattern: Various element interactions are slow\n\n## Pattern: Various element interactions are slow > ### Symptoms\n\nYou observe timeouts or unusual slowness while clicking elements or performing other\nactions on them.\n\n## Pattern: Various element interactions are slow > ### Causes\n\n- The current app hierarchy is too large (e.g. has hundreds of elements). This is a known\n XCTest limitation.\n- The app is not idling/has active animations\n\n## Pattern: Various element interactions are slow > ### Solutions\n\n- Reduce various timeouts similarly to how it's advised in the\n [Application startup is slow](#pattern-application-startup-is-slow) pattern\n- Fix the source code of the application under test to reduce the amount of accessible elements\n on a single screen\n- Fix the source code of the application under test to avoid running long operations\n or animations on the main thread\n\n## Pattern: Page source retrieval slow\n\n## Pattern: Page source retrieval slow > ### Symptoms\n\nYou observe timeouts or unusual slowness while retrieving the page of the app.","metadata":{"headerPath":"## Pattern: Element location with non-XPath is slow > ### Solutions","sectionCount":7,"filename":"wda-slowness.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-slowness.md"}},{"pageContent":"## Pattern: Page source retrieval slow > ### Causes\n\nIn order to retrieve the page source WDA needs to take a snapshot of the whole accessibility\nhierarchy with all element attributes resolved, which is a time-expensive operation.\nPage source retrieval slowness might be observed if:\n- The current app hierarchy is too large (e.g. has hundreds of elements). This is a known\n XCTest limitation.\n- The app is not idling/has active animations\n- It takes too long to determine each element's `visible` or `accessible` attributes, which are custom\n ones and are not present in the original XCTest implementation\n\n## Pattern: Page source retrieval slow > ### Solutions\n\n- Reduce the size of the app hierarchy using the [snapshotMaxDepth setting](../reference/settings.md).\n Note that you won't see nested elements in the source tree whose nesting level is greater than\n the given size.\n- Retrieve the page source without \"expensive\" attributes using the\n [mobile: source](../reference/execute-methods.md#mobile-source) method with\n the appropriate `excludedAttributes` argument value or add such attribute names into\n the [pageSourceExcludedAttributes setting](../reference/settings.md).\n- Retrieve the native XCTest page source using the\n [mobile: source](../reference/execute-methods.md#mobile-source) method with\n the `format=description` argument value. The returned page source is a poorly-formatted text,\n although its retrieval should be fast (at least not slower than XCTest does that).\n- Reduce various timeouts similarly to how it's advised in the\n [Application startup is slow](#pattern-application-startup-is-slow) pattern\n- Fix the source code of the application under test to reduce the amount of accessible elements\n on a single screen\n- Fix the source code of the application under test to avoid running long operations\n or animations on the main thread","metadata":{"headerPath":"## Pattern: Page source retrieval slow > ### Causes","sectionCount":2,"filename":"wda-slowness.md","relativePath":"appium-xcuitest-driver/docs/guides/wda-slowness.md"}},{"pageContent":"---\nhide:\n - navigation\n - toc\n\ntitle: Welcome\n---\n<style>\n .md-typeset h1 {\n display: none;\n }\n</style>\n\n<div style=\"text-align: center\">\n <img src=\"assets/images/appium-plus-xctest.png\" style=\"max-width: 500px;\" />\n</div>\n\nWelcome to the Appium XCUITest Driver documentation! The XCUITest driver is a test automation\nframework for iOS, iPadOS and tvOS devices, enabling automated black-box testing of native, hybrid\nand WebKit web apps, on both emulators and real devices. \n\nThe XCUITest driver is part of the Appium test automation tool. For information on Appium itself,\nplease visit [the Appium documentation](https://appium.io).\n\n## Explore the Documentation\n\n<div class=\"grid cards\" markdown>\n\n- Check out the [__Overview__](./overview.md) to learn how the driver works\n- Go through the [__Installation__](./installation/index.md) steps to get set up\n- Follow the [__Device Preparation__](./preparation/index.md) instructions to configure your test device\n- Browse the [__Reference__](./reference/scripts.md) documentation for everything exposed by the driver\n- Read the different [__Guides__](./guides/parallel-tests.md) for a variety of instructions, tips and tricks\n- For contributions to the driver, refer to the [__Contributing__](./contributing.md) page\n\n</div>","metadata":{"headerPath":"","sectionCount":2,"filename":"index.md","relativePath":"appium-xcuitest-driver/docs/index.md"}},{"pageContent":"---\nhide:\n - navigation\n\ntitle: Installation\n---\n\nLike all Appium drivers, the XCUITest driver requires Appium to be installed. Refer to the\n[Appium documentation](https://appium.io/docs/en/latest/quickstart/install/) for its requirements\nand prerequisites.\n\n!!! info\n\n XCUITest driver `10.0.0` or later requires Appium 3, and no longer supports Appium 2. For more\n details, refer to the [Appium Server Support](#appium-server-support) section.\n\n## Install the Driver\n\nOnce Appium has been installed, you can use the [extension CLI](https://appium.io/docs/en/latest/cli/extensions/)\nto install the XCUITest driver:\n\n```bash\nappium driver install xcuitest\n```\n\nAlternatively, if you are running a Node.js project, you can include `appium-xcuitest-driver` as\none of your project dependencies. [Refer to the Appium documentation](https://appium.io/docs/en/latest/guides/managing-exts/#do-it-yourself-with-npm)\nfor more information about this approach.\n\n## Load the Driver\n\nTo activate the driver, simply launch the Appium server. By default, Appium will load all the\ninstalled drivers:\n\n```bash\nappium\n```\n\nThe server log output should include a line like the following:\n\n```\n[Appium] XCUITestDriver has been successfully loaded in 0.789s\n```\n\nOnce the driver has been loaded, you can continue with [device preparation](../preparation/index.md).","metadata":{"headerPath":"","sectionCount":3,"filename":"index.md","relativePath":"appium-xcuitest-driver/docs/installation/index.md"}},{"pageContent":"## System Requirements\n\n!!! note\n\n Many of the below requirements can be validated after installing the driver, via the built-in\n Appium Doctor support:\n ```\n appium driver doctor xcuitest\n ```\n\n- macOS host platform\n- Xcode and Xcode Developer Tools\n - Make sure to install an Xcode version that supports the iOS/iPadOS/tvOS version you want to test.\n Different Xcode versions also have different macOS host version requirements. For more details,\n refer to the [Xcode Release Notes](https://developer.apple.com/documentation/xcode-release-notes/).\n - New major Xcode versions (especially beta) will likely require you to also update the driver. See the\n [iOS Version Support](#ios-version-support) section for details.\n- If automating real devices, additional manual configuration is required - please refer to the\n [Real Device Configuration](../preparation/real-device-config.md) guide.\n- If testing web or hybrid apps, their webviews must be debuggable. If it is not possible to connect to your\n webview(s) using [Safari remote debugger](https://appletoolbox.com/use-web-inspector-debug-mobile-safari/),\n then the driver will not be able to identify them.\n\n## System Requirements > ### Optional Requirements\n\n- [`xcpretty`](https://github.com/supermarin/xcpretty) can be used to make Xcode output easier to\n read. It can be installed by running `gem install xcpretty`.\n- [`ffmpeg`](https://ffmpeg.org/) is used for test video recording. It can be installed using\n [`brew`](https://brew.sh/): `brew install ffmpeg`\n- [`idb`](https://github.com/facebook/idb), [`go-ios`](https://github.com/danielpaulus/go-ios) and\n [`tidevice`](https://github.com/alibaba/taobao-iphone-device) can be used to improve device interactions\n- [WIX AppleSimulatorUtils](https://github.com/wix/AppleSimulatorUtils) can be used to improve some\n Simulator interactions\n- [`py-ios-device`](https://github.com/YueChen-C/py-ios-device) is required in several `mobile:`\n extensions, and can improve the general testing experience for real devices\n\n## Appium Server Support\n\nIf you are running an older version of Appium, make sure to install a supported driver version:\n\n| Appium server version | Supported XCUITest driver versions |\n| --- | --- |\n| Appium 3 | `>= 10.0.0` |\n| Appium 2 | `4.0.0 - 9.10.5` |\n| Appium 1 | `<= 3.62.0` (bundled with Appium) |","metadata":{"headerPath":"## System Requirements","sectionCount":3,"filename":"index.md","relativePath":"appium-xcuitest-driver/docs/installation/index.md"}},{"pageContent":"## iOS Version Support\n\nDifferent driver versions support different ranges of iOS/iPadOS/tvOS versions. The following tables\nshould help you decide which driver version to install. If you are upgrading/downgrading an\nexisting installation, check that the [WebDriverAgent (WDA)](https://github.com/appium/WebDriverAgent)\nversion on the device under test is also updated accordingly.\n\nFor iOS/tvOS support in driver versions older than `4.0.0` (Appium 1), please refer to\n[the Appium 1 changelog](https://github.com/appium/appium/blob/1.x/CHANGELOG.md).\n\n!!! info \"Background\"\n\n The XCUITest driver depends on the [WebDriverAgent (WDA)](https://github.com/appium/WebDriverAgent)\n framework, which in turn [relies on Apple's XCTest framework](../overview.md). Changes in the\n XCTest API are published in new Xcode and Apple device OS versions. These API changes may\n add new features that the driver must implement in order to support the latest devices, as well\n as modify or even remove support for existing features that the driver relies on. In both cases,\n new driver and WDA versions are required.\n\nGenerally, the driver/WDA aims to support the latest _two_ (2) major Xcode/iOS/iPadOS/tvOS versions,\nbut may also work with older versions, unless specified below.\n\nThe following are the minimum driver/WDA versions required for specific Xcode/iOS versions:\n\n| Xcode/iOS version | Minimum XCUITest driver & WDA version |\n| --- | --- |\n| Xcode 26 / iOS 26 | `9.5.0` (WDA `9.14.1`) |\n| Xcode 16-beta.5 / iOS 18 | `7.24.15` (WDA `8.9.1`) |\n| Xcode 15 / iOS 17 | `4.32.23` (WDA `5.6.0`) |\n| Xcode 14.3 / iOS 16.4 | `4.21.7` (WDA `4.13.1`) |\n| Xcode 14-beta.3 / iOS 16 Beta | `4.7.4` (WDA `4.8.1`) |\n\nThe following are the last driver versions that are compatible with older Xcode versions:\n\n| Xcode version | Last supported XCUITest driver version |\n| --- | --- |\n| Xcode 13 | `10.6.0` (WDA `10.2.2`) |\n| Xcode 12 | `4.27.2` (WDA `4.15.1`) |\n| Xcode 11 | `4.2.0` (WDA `4.0.0`) |\n\nThe following are the last driver versions that are compatible with older iOS versions:\n\n| iOS version | Last supported XCUITest driver version |\n| --- | --- |\n| iOS 9 - iOS 14 | `4.27.2` (WDA `4.15.1`) |\n| iOS 8 | `4.2.0` (WDA `4.0.0`) |","metadata":{"headerPath":"## iOS Version Support","sectionCount":1,"filename":"index.md","relativePath":"appium-xcuitest-driver/docs/installation/index.md"}},{"pageContent":"---\nhide:\n - navigation\n - toc\n\ntitle: Overview\n---\n\nThe XCUITest driver combines several different technologies to achieve its functionality:\n\n- Native testing is based on Apple's [XCTest](https://developer.apple.com/documentation/xctest) framework\n and Appium's fork of Facebook's [WebDriverAgent](https://github.com/appium/WebDriverAgent) server\n (the [original](https://github.com/facebookarchive/WebDriverAgent) project is not supported anymore)\n - In native mode, the driver operates in scope of [WebDriver W3C protocol](https://w3c.github.io/webdriver)\n with several platform-specific extensions\n- Webview communication is done via [Webkit remote debugger protocol](https://github.com/appium/appium-remote-debugger)\n - In webview mode, the driver can only operate in scope of the obsolete [JSONWP protocol](https://webdriver.io/docs/api/jsonwp.html)\n- Real device communication is provided by the [`appium-ios-device`](https://github.com/appium/appium-ios-device) library\n- Simulator communication is provided by the [`appium-ios-simulator`](https://github.com/appium/appium-ios-simulator) library","metadata":{"headerPath":"","sectionCount":1,"filename":"overview.md","relativePath":"appium-xcuitest-driver/docs/overview.md"}},{"pageContent":"---\ntitle: Device Preparation\n---\n\nBefore using the XCUITest driver with a simulator or real device, some device preparation is required.\n\n## Automatic Adjustments\n\nThe XCUITest driver automatically adjusts some device preferences for testing purposes.\n\n## Automatic Adjustments > ### Keyboard Configuration\n\nSome keyboard preferences are changed in order to make test runs more stable. You can change some\nof them via the [Settings API](https://appium.io/docs/en/latest/guides/settings/).\n\n- _Settings -> General -> Keyboard -> Auto-Correction_ is turned OFF\n- _Settings -> General -> Keyboard -> Predictive Text_ is turned OFF\n- The keyboard tutorial is marked as complete\n- (Simulator Only) Software keyboard is turned ON\n\n## Manual Adjustments\n\nUnfortunately, not all configuration can be done automatically, and some changes must be applied manually.\n\n## Manual Adjustments > ### Accessibility Settings\n\n- To avoid miscalculation of element coordinates, please make sure the zoom preference is turned off\n in _Settings -> Accessibility -> Zoom_.\n- Some accessibility settings may expose additional view elements. Appium does not modify these\n settings automatically, since they could affect the way your application under test performs.\n Please change them manually if needed. Note that the available accessibility content depends on\n the OS version.\n - _Settings -> Accessibility -> Spoken Content -> Speak Selection_","metadata":{"headerPath":"","sectionCount":5,"filename":"index.md","relativePath":"appium-xcuitest-driver/docs/preparation/index.md"}},{"pageContent":"## Manual Adjustments > ### Webview Testing\n\n- Webviews on iOS/iPadOS 16.4 or above may require additional configuration from the application developer.\n Specifically, the destination `WKWebView` and/or `JSContext` component must have the\n [`isInspectable`](https://developer.apple.com/documentation/webkit/wkwebview/4111163-isinspectable)\n property set to `true`. Please read [the WebKit documentation page](https://webkit.org/blog/13936/enabling-the-inspection-of-web-content-in-apps/)\n for more details on this property.\n - WebViews on iOS/iPadOS below version 16.4 must have the [`get-task-allow` entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_debugger) present as `true` in the application manifest.\n- Starting from iOS/iPadOS 16.4, the Google Chrome browser also supports webview testing. This feature\n requires Chrome version 115 or newer. Please read\n [the Chrome Developer documentation page](https://developer.chrome.com/blog/debugging-chrome-on-ios/)\n for details on the necessary configuration.\n\n## Manual Adjustments > ### Real Devices\n\nSome settings are enabled by default on simulators, but need to be manually changed for real devices.\nSee the [Real Device Configuration](./real-device-config.md) document for details.","metadata":{"headerPath":"## Manual Adjustments > ### Webview Testing","sectionCount":2,"filename":"index.md","relativePath":"appium-xcuitest-driver/docs/preparation/index.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Basic Automatic Configuration\n---\n\nIf you have a paid Apple Developer account, the easiest way to create the provisioning profile is\nto use the automatic configuration strategy. There are two ways to do this:\n\n* Use the `xcodeOrgId` and `xcodeSigningId` [capabilities](../reference/capabilities.md):\n ```json\n {\n \"appium:xcodeOrgId\": \"<Team ID>\",\n \"appium:xcodeSigningId\": \"Apple Developer\",\n \"appium:updatedWDABundleId\": \"<bundle id your provisioning profile can accept>\"\n }\n ```\n* Create a `.xcconfig` file somewhere on your file system and add the following to it:\n ```ini\n DEVELOPMENT_TEAM = <Team ID>\n CODE_SIGN_IDENTITY = Apple Developer\n ```\n Then use the `xcodeConfigFile` capability to specify the path to this file:\n ```json\n {\n \"appium:xcodeConfigFile\": \"/path/to/xcconfig/file\"\n }\n ```\n\nNote that these are mutually exclusive strategies; use _either_ the `appium:xcodeConfigFile` capability\n_or_ the combination of `appium:xcodeOrgId` and `appium:xcodeSigningId`.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"prov-profile-basic-auto.md","relativePath":"appium-xcuitest-driver/docs/preparation/prov-profile-basic-auto.md"}},{"pageContent":"Note that these are mutually exclusive strategies; use _either_ the `appium:xcodeConfigFile` capability\n_or_ the combination of `appium:xcodeOrgId` and `appium:xcodeSigningId`.\n\n* `appium:xcodeOrgId` / `DEVELOPMENT_TEAM` is a unique 10-character string generated by Apple that is\n assigned to your team.\n * To find this string (your Team ID), sign in to [developer.apple.com/account](https://developer.apple.com/account),\n and click Membership in the sidebar. Your Team ID appears in the Membership Information\n section under the team name. You can also find your Team ID listed under the \"Organizational\n Unit\" field in your iPhone Developer certificate in your keychain.\n* `appium:xcodeSigningId` / `CODE_SIGN_IDENTITY` is usually either `Apple Developer` or `iPhone Developer`.\n* `appium:updatedWDABundleId` is the bundle id you would like to use for the built WebDriverAgent.\n * Appium replaces the existing placeholder of `com.facebook.WebDriverAgentRunner` in `WebDriverAgent.xcodeproj` with the given capability value.\n * `xcodebuild` adds `.xctrunner` automatically for XCTest package. Thus, the provisioning profile you're using should have the suffix explicitly, or it can be for bundle id which has `*`.\n * For instance, when the `appium:updatedWDABundleId` is `io.appium.WebDriverAgentRunner`, the given provisioning profile should be for `io.appium.WebDriverAgentRunner.xctrunner`, `io.appium.WebDriverAgentRunner.*` or `*`.\n * `appium:allowProvisioningDeviceRegistration` lets XCUITest driver set `-allowProvisioningUpdates` and `-allowProvisioningDeviceRegistration` flags for the `xcodebuild` command. They will help register the target device to the matched provisioning profile if it still doesn't have the device. Please check `man xcodebuild` output for more details.\n\nOnce this configuration is done, you should specify your real device UDID with the `udid` desired\ncapability, after which you should be able to start your test. Proceed with\n[Validating the WDA Install](./real-device-config.md#validating-the-wda-install) for the next steps.","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"prov-profile-basic-auto.md","relativePath":"appium-xcuitest-driver/docs/preparation/prov-profile-basic-auto.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Basic Manual Configuration\n---\n\nThere are many cases in which the basic automatic configuration is not enough. Often this happens\nwhen the development account being used is a \"Free\" one, in which case it is not possible to create\na wildcard provisioning profile.\n\nYou can confirm this by opening the WDA project in Xcode. The issue will manifest as something like\nan error that Xcode failed to create provisioning profile:\n\n![No provisioning profile](./assets/images/no-prov-prof.png)\n\nThe easiest way around this is to create a new project:\n\n![Create new project](./assets/images/create-new-project.png)\n\nThe type does not matter, other than it being \"iOS\". \"Single View Application\" is the easiest:\n\n![Create single page](./assets/images/create-single-page.png)\n\nThe important part is to use a unique \"Product Name\" and \"Organization Name\". Also, at this point,\nspecify your \"Team\".\n\n![Setup bundle](./assets/images/set-up-bundle.png)\n\nYou can confirm that the provisioning profile was created by looking at the \"Project\" tab:\n\n![Project pane](./assets/images/project-prov-prof.png)\n\nOr by going into your account preferences and seeing the provisioning profile:\n\n![Check provisioning profile](./assets/images/check-prov-prof.png)\n\nAt this point you have a valid provisioning profile. Make note of the bundle identifier\nyou associated with it, and add that in the `updatedWDABundleId` capability for your tests.\nThen follow the [initial instructions for automatic configuration](./prov-profile-basic-auto.md).","metadata":{"headerPath":"","sectionCount":1,"filename":"prov-profile-basic-manual.md","relativePath":"appium-xcuitest-driver/docs/preparation/prov-profile-basic-manual.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Full Manual Configuration\n---\n\nThe provisioning profile can also be manually associated with the WDA project. Keep in mind that\nthis will have to be done each time WDA is updated (such as when updating the XCUITest driver),\nand is _not_ recommended:\n\n* In the terminal, open the directory where WDA is located. Run the following to set the project up:\n ```bash\n mkdir -p Resources/WebDriverAgent.bundle\n ```\n* Open `WebDriverAgent.xcodeproj` in Xcode. This will likely open a screen with an empty editor.\n* In the file browser on the left side, select the root _WebDriverAgent_ project, which will open\n it in the editor. Then, under _Targets_, select _WebDriverAgentRunner_ (or\n _WebDriverAgentRunner\\_tvOS_ for tvOS), and switch to the _Signing & Capabilities_ tab.\n* Check _Automatically manage signing_, and then select your _Team_ (you may need to first sign\n into Xcode). The outcome should be similar to the following:\n\n ![WebDriverAgent in Xcode project](./assets/images/xcode-config.png)\n\n* Xcode will likely fail to create a provisioning profile due to an invalid bundle identifier:\n\n ![Xcode provisioning fail](./assets/images/xcode-facebook-fail.png)\n\n* Change the _Bundle Identifier_ from `com.facebook.WebDriverAgentRunner` to something that Xcode\n will accept. You can also do this in the _Build Settings_ tab:\n\n ![Xcode bundle id](./assets/images/xcode-bundle-id.png)\n \n!!! note\n\n Versions of Xcode older than 11 have a different naming convention. This feature may not work\n for a package which is built by Xcode versions below 12.\n\n* If your bundle identifier is accepted, you should see that Xcode has created a provisioning\n profile and all is well:\n\n ![Xcode provisioning profile](./assets/images/xcode-facebook-succeed.png)\n\n* Finally, you can verify that everything works:\n * Select the scheme as _Product -> Scheme -> WebDriverAgentRunner_\n * Select your real device in _Product -> Destination_\n * Select _Product -> Test_ to build and install the WDA app\n\nProceed with [Validating the WDA Install](./real-device-config.md#validating-the-wda-install) for\nthe next steps!","metadata":{"headerPath":"","sectionCount":1,"filename":"prov-profile-full-manual.md","relativePath":"appium-xcuitest-driver/docs/preparation/prov-profile-full-manual.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Manual Configuration for a Generic Device\n---\n\nIt is possible to build `WebDriverAgentRunner` for a generic iOS/iPadOS/tvOS device, and install the\ngenerated `.app` package to a real device.\n\n```bash\n# iOS/iPadOS\n$ xcodebuild clean build-for-testing -project WebDriverAgent.xcodeproj -derivedDataPath appium_wda_ios -scheme WebDriverAgentRunner -destination generic/platform=iOS CODE_SIGNING_ALLOWED=YES\n\n# tvOS\n$ xcodebuild clean build-for-testing -project WebDriverAgent.xcodeproj -derivedDataPath appium_wda_tvos -scheme WebDriverAgentRunner_tvOS -destination generic/platform=tvOS CODE_SIGNING_ALLOWED=YES\n```\n\nOn successful completion the resulting package `WebDriverAgentRunner-Runner.app` should be located\nin the `Build/Products/Debug-iphoneos/` subfolder under WebDriverAgent sources root, or in the path\nprovided as `derivedDataPath` argument.\n\n!!! note\n\n If the build fails, please make sure `WebDriverAgent.xcodeproj` has codesigning properties\n configured properly. For example, you may need to change the bundle id for the provisioning profile.\n\nThe `WebDriverAgentRunner-Runner.app` can now be installed to any real device as allowed by the\nprovisioning profile.\n\nYou can install the package with 3rd party tools and manage it separately as explained in\n[How To Set Up And Customize WebDriverAgent Server](../guides/wda-custom-server.md). Note that if\nthe codesigning was not correct, the installation will fail.\n\nAs a more advanced method, you can generate the package with `CODE_SIGNING_ALLOWED=NO` and do\n[`codesign`](https://developer.apple.com/documentation/xcode/using-the-latest-code-signature-format)\nby yourself. This would make the device management more flexible, but you would need to know about\nadvanced codesign usage scenarios.\n\n!!! note\n\n The Appium team distributes generic builds with `CODE_SIGNING_ALLOWED=NO` at\n [WebDriverAgent package releases](https://github.com/appium/WebDriverAgent/releases).\n It is recommended to sign packages with a wildcard (`*`) provisioning profile,\n although such profiles require a paid Apple Developer account.\n For example, if you're preparing such a provisioning profile for `io.appium.WebDriverAgentRunner.xctrunner`, it will be for `io.appium.*`, `io.appium.WebDriverAgentRunner.*` or `*`.\n In case of a free account, you may need to update the bundle id before building\n the WebDriverAgent package to prepare a properly signed WebDriverAgent package\n by `xcodebuild`.","metadata":{"headerPath":"","sectionCount":1,"filename":"prov-profile-generic-manual.md","relativePath":"appium-xcuitest-driver/docs/preparation/prov-profile-generic-manual.md"}},{"pageContent":"---\ntitle: Real Device Configuration\n---\n\nIn order to communicate with the device under test, the XCUITest driver automatically installs the\n`WebDriverAgentRunner-Runner` (WDA) application on it, using Xcode's command-line utility `xcodebuild`.\nUnlike simulators, real devices have several security restrictions that need to be manually\nconfigured, before this can work:\n\n- Devices need to be trusted. This can be done by opening Xcode and afterwards physically connecting\n the device under test to the computer. The device should have a popup asking to trust the computer,\n which you should accept.\n- Devices using iOS/iPadOS 16 or above require enabling Developer Mode. Please read\n [Apple's documentation on Developer Mode](https://developer.apple.com/documentation/xcode/enabling-developer-mode-on-a-device)\n for more details. `devmodectl streaming` CLI on macOS 13+ and installing development signed apps\n also help enabling the mode.\n- After enabling Developer Mode (if applicable), please turn on _Settings -> Developer -> Enable UI Automation_\n- Webviews will not be testable unless the Safari Inspector is enabled. Please turn it on in\n _Settings -> Safari -> Advanced -> Web Inspector_. Similarly, you may want to turn on the adjacent\n option _Settings -> Safari -> Advanced -> Remote Automation_.\n\nFinally, the WDA application must have a valid provisioning profile, which includes signing the app\nand linking it to a development team.","metadata":{"headerPath":"","sectionCount":1,"filename":"real-device-config.md","relativePath":"appium-xcuitest-driver/docs/preparation/real-device-config.md"}},{"pageContent":"## Provisioning Profile Setup\n\nGenerally, unless your device under test [already has WDA installed](../guides/run-preinstalled-wda.md),\nor you already have [a prebuilt WDA](../guides/run-prebuilt-wda.md) on your local system, you will\nneed an Apple ID to be able to sign the app.\n\nOnce you have an Apple ID, there are several approaches you can take.\n\n* [__Basic Automatic Configuration__](./prov-profile-basic-auto.md): the easiest approach, but\n requires you to have a paid Apple Developer account\n\nIf the automatic configuration did not work or does not apply to you, you will need to follow one of\nthe manual configuration approaches. All of these involve the WDA Xcode project, so at the very\nleast, you must know the local path to the project file - `WebDriverAgent.xcodeproj`:\n\n* The WDA project is included in `appium-webdriveragent`, which is installed as a dependency of the\n XCUITest driver. You can therefore find the project file in\n `/path/to/xcuitest/driver/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj`.\n By default, drivers are installed in `~/.appium`, so the project would be located at\n `~/.appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj`.\n* If using XCUITest driver v4.13.0 or newer, you can run the `appium driver run xcuitest open-wda`\n [driver script](../reference/scripts.md) to directly open `WebDriverAgent.xcodeproj` in Xcode.\n\nThe WDA project file can now be used in the manual configuration approaches:\n\n* [__Basic Manual Configuration__](./prov-profile-basic-manual.md): create a new project, then use\n its provisioning profile and bundle ID\n* [__Full Manual Configuration__](./prov-profile-full-manual.md): associate the provisioning profile\n directly with the WDA project\n* [__Manual Configuration for a Generic Device__](./prov-profile-generic-manual.md): manually run\n `xcodebuild` to build WDA, then manually install it","metadata":{"headerPath":"## Provisioning Profile Setup","sectionCount":1,"filename":"real-device-config.md","relativePath":"appium-xcuitest-driver/docs/preparation/real-device-config.md"}},{"pageContent":"## Provisioning Profile Setup > ### Validating the WDA Install\n\nOnce you have configured the WDA project or have the app ready, you can try installing it. It is\npossible that you may encounter some errors:\n\n* `xcodebuild exited with code '65' and signal 'null'`\n\n This usually happens when attempting the automatic configuration, and it means that the necessary\n code signing is not set up correctly. Follow the steps in any of the manual configuration\n approaches to fix this.\n\n* `Unable to launch <your-bundle-id>.WebDriverAgentRunner-Runner because it has an invalid code\n signature, inadequate entitlements or its profile has not been explicitly trusted by the user.`\n\n This means that the developer is not trusted on the device. If you manually try to open the WDA\n app on the device, you will see a popup message:\n\n ![Untrusted developer](./assets/images/untrusted-dev.png)\n\n To fix this, you need to open _Settings -> General -> VPN & Device Management_ on the device, then\n select your development team and trust it. Afterwards you should be able to open/launch the app.\n See [Apple documentation for more information](https://support.apple.com/en-us/HT204460).\n\n* For other issues, please refer to the [Troubleshooting](../guides/troubleshooting.md) page\n\n## Provisioning Profile Setup > ### Create an Offline Provisioning Profile\n\nSince iOS 16, Apple requires a device to have a live internet connection for validating the code\nsigning. It is possible to set up an offline enabled provisioning profile, which allows you to avoid\nthe limitation. Please read [this issue](https://github.com/appium/appium/issues/18378#issuecomment-1482678074)\nregarding detailed configuration steps.\n\n## Tune WebDriverAgent to improve session startup performance\n\nRunning `xcodebuild` every time takes much longer time to complete a session startup.\nXCUITest driver offers a few methods to improve the performance with, or without using `xcodebuild`.\n\nSome might require deeper understanding of iOS development environment,\nbut they help to improve speedup your test execution speed.\n\n- [Run Preinstalled WebDriverAgentRunner](./../guides/run-preinstalled-wda.md)\n- [Run Prebuilt WebDriverAgentRunner](./../guides/run-prebuilt-wda.md)\n- [Attach to a Running WebDriverAgent](./../guides/attach-to-running-wda.md)","metadata":{"headerPath":"## Provisioning Profile Setup > ### Validating the WDA Install","sectionCount":3,"filename":"real-device-config.md","relativePath":"appium-xcuitest-driver/docs/preparation/real-device-config.md"}},{"pageContent":"---\ntitle: BiDi Protocol Support\n---\n\nXCUITest driver has partial support of the [BiDi Protocol](https://w3c.github.io/webdriver-bidi/) since version 7.26.0.\nOnly events and commands mentioned below are supported.\nAll other entities described in the spec throw not implemented errors.\n\n# Supported Events\n\n# Supported Events > ## log.entryAdded\n\nThis event is emitted if the driver retrieves a new entry for any of the below log types. Logs collection might be disabled by the `appium:skipLogCapture` capability.\n\n# Supported Events > ## log.entryAdded > ### crashlog\n\nEvents are emitted for both emulator and real devices. The latter only works if [py-ios-device](https://github.com/YueChen-C/py-ios-device) is installed on the server host. Each event contains a particular device crash report entry.\nEvents are always emitted with the `NATIVE_APP` context.\n\n# Supported Events > ## log.entryAdded > ### syslog\n\nEvents are emitted for both emulator and real devices. Each event contains a single device system log line.\nEvents are always emitted with the `NATIVE_APP` context.\n\n# Supported Events > ## log.entryAdded > ### safariConsole\n\nEvents are emitted for both emulator and real devices. Each event contains a single Safari console log line.\nEvents are always emitted with the appropriate web context name from which they were generated.\nEvents are only emitted if the `appium:showSafariConsoleLog` capability value is provided.\n\n# Supported Events > ## log.entryAdded > ### safariNetwork\n\nEvents are emitted for both emulator and real devices. Each event contains a single Safari network log line.\nEvents are always emitted with the appropriate web context name from which they were generated.\nEvents are only emitted if the `appium:showSafariNetworkLog` capability value is provided.\n\n# Supported Events > ## log.entryAdded > ### performance\n\nEvents are emitted for both emulator and real devices. Each event contains a single Safari performance log line.\nEvents are always emitted with the appropriate web context name from which they were generated.\nEvents are only emitted if the `appium:enablePerformanceLogging` capability value is provided.\n\n# Supported Events > ## log.entryAdded > ### server\n\nEvents are emitted for both emulator and real devices. Each event contains a single Appium server log line.\nEvents are always emitted with the `NATIVE_APP` context.\nEvents are only emitted if the `get_server_logs` server security feature is enabled.","metadata":{"headerPath":"","sectionCount":9,"filename":"bidi.md","relativePath":"appium-xcuitest-driver/docs/reference/bidi.md"}},{"pageContent":"# Supported Events > ## appium:xcuitest.contextUpdate\n\nThis event is emitted upon the context change, either explicit or implicit.\nThe event is always emitted upon new session initialization.\nSee the [GitHub feature ticket](https://github.com/appium/appium/issues/20741) for more details.\n\n# Supported Events > ## appium:xcuitest.contextUpdate > ### CDDL\n\n```cddl\nappium:xcuitest.contextUpdated = {\n method: \"appium:xcuitest.contextUpdated\",\n params: {\n name: text,\n type: \"NATIVE\" / \"WEB\",\n },\n}\n```\n\nThe event contains the following params:\n\n# Supported Events > ## appium:xcuitest.contextUpdate > ### name\n\nContains the actual name of the new context, for example `NATIVE_APP`.\n\n# Supported Events > ## appium:xcuitest.contextUpdate > ### type\n\nEither `NATIVE` or `WEB` depending on which context is currently active in the driver session.","metadata":{"headerPath":"# Supported Events > ## appium:xcuitest.contextUpdate","sectionCount":4,"filename":"bidi.md","relativePath":"appium-xcuitest-driver/docs/reference/bidi.md"}},{"pageContent":"---\ntitle: Capabilities\n---\n\nThis page lists various capabilities used and implemented by the XCUITest driver. To learn more\nabout capabilities, refer to the [Appium documentation](https://appium.io/docs/en/latest/guides/caps/).","metadata":{"headerPath":"","sectionCount":1,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### General\n\n| <div style=\"width:10em\">Capability</div> | Description |\n| --- | --- |\n| `platformName` | Could be set to `ios`. Appium itself is not strict about this capability value if `automationName` is provided, so feel free to assign it to any supported platform name if this is needed, for example, to make Selenium Grid working. |\n| `browserName` | The name of the browser to run the test on. If this capability is provided then the driver will try to start the test in Web context mode (Native mode is applied by default). Read [Automating hybrid apps](../guides/hybrid.md) for more details. Usually equals to `safari`. |\n| `appium:automationName` | Must always be set to `xcuitest`. Values of `automationName` are compared case-insensitively. |\n| `appium:deviceName` | The name of the device under test. Consider setting `udid` for real devices and use this one for Simulator selection instead |\n| `appium:platformVersion` | The platform version of an emulator or a real device. This capability is used for device autodetection if `udid` is not provided |\n| `appium:udid` | UDID of the device to be tested. Could be retrieved from Xcode->Window->Devices and Simulators window. Always set this capability if you run parallel tests or use a real device to run your tests. |\n| `appium:noReset` | Prevents the device to be reset before the session startup if set to `true`. This means that the application under test is not going to be terminated neither its data cleaned. `false` by default |\n| `appium:fullReset` | Being set to `true` always enforces the application under test to be fully uninstalled before starting a new session. The application data might be cached on real devices under particular circumstances. Please check [troubleshooting](../guides/troubleshooting.md#leftover-application-data-on-real-devices) for more details regarding obsolete application data cleanup on real devices. `false` by default |\n| `appium:printPageSourceOnFindFailure` | Enforces the server to dump the actual XML page source into the log if any error happens. `false` by default. |","metadata":{"headerPath":"### General","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### General\n\n| `appium:printPageSourceOnFindFailure` | Enforces the server to dump the actual XML page source into the log if any error happens. `false` by default. |\n| `appium:includeDeviceCapsToSessionInfo` | Whether to include screen information as the result of [Get Session Capabilities](https://appium.io/docs/en/latest/commands/base-driver/#getsession/). It includes `pixelRatio`, `statBarHeight` and `viewportRect`, but it causes an extra API call to WDA which may increase the response time like [this issue](https://github.com/appium/appium/issues/15101). Defaults to `true`. **This capability has no effect since driver version 5** |\n| `appium:resetLocationService` | Whether reset the location service in the session deletion on real device. Defaults to `false`. |\n| `appium:customSSLCert` | Adds a root SSL certificate to IOS Simulators and real devices. Real devices only work if [py-ios-device](https://github.com/YueChen-C/py-ios-device) tool is available on the server machine. The certificate content must be provided in [PEM](https://knowledge.digicert.com/quovadis/ssl-certificates/ssl-general-topics/what-is-pem-format.html) format, e.g. ```-----BEGIN CERTIFICATE-----MIIFWjCCBEKg...-----END CERTIFICATE-----``` |","metadata":{"headerPath":"### General","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### App\n\n| <div style=\"width:10em\">Capability</div> | Description |\n| --- | --- |\n| `appium:bundleId` | Bundle identifier of the app under test, for example `com.mycompany.myapp`. The capability value is calculated automatically if `app` is provided. If neither `app` or `bundleId` capability is provided then XCUITest driver starts from the Home screen. |\n| `appium:initialDeeplinkUrl` | A deeplink URL used to run either the application assigned to `appium:bundleId`, or the default application assigned to handle the particular deeplink protocol if `appium:bundleId` is not set. If provided in combination with `browserName=safari` then makes Safari to start with the given URL preloaded, which speeds up the session startup. The value of `appium:initialSafariUrl` capability is ignored in such case. An error is thrown on session init if either the value of the capability is not a valid URL, or XCTest was not able to associate it with any existing app, or the actual iOS version is below *16.4* |\n| `appium:app` | Full path to the application to be tested (the app must be located on the same machine where the server is running). `.ipa` and `.app` application extensions are supported. Zipped `.app` bundles are supported as well. Could also be an URL to a remote location. If neither of the `app` or `bundleId` capabilities are provided then the driver starts from the Home screen and expects the test to know what to do next. Do not provide both `app` and `browserName` capabilities at once. |","metadata":{"headerPath":"### App","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### App\n\n| `appium:enforceAppInstall` | If set to `false` it will make xcuitest driver to verify whether the app version currently installed on the device under test is older than the one, which is provided as `appium:app` value. No app reinstall is going to happen if the candidate app has the same or older version number than the already installed copy of it. The version number used for comparison must be provided as [CFBundleVersion](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion) [Semantic Versioning](https://semver.org/)-compatible value in the application's Info.plist. No validation is performed by default, e.g. the provided app is always (re)installed, which could potentially slow down your test suites. The application data might be cached on real devices under particular circumstances when `appium:enforceAppInstall` is `true` if the application under test remained on the device under a certain situation. Please check [troubleshooting](../guides/troubleshooting.md#leftover-application-data-on-real-devices) for more details regarding obsolete application data cleanup on real devices. Available since XCUITest driver 4.19.0. | false |\n| `appium:localizableStringsDir` | Where to look for localizable strings in the application bundle. Defaults to `en.lproj` |\n| `appium:otherApps` | App or list of apps (as a JSON array) to install prior to running tests. For example: `[\"http://appium.github.io/appium/assets/TestApp9.4.app.zip\", \"/path/to/app-b.app\"]` |\n| `appium:language` | Language to set for iOS app, for example `fr`. Please read [Language IDs](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html) to get more details about available values for this capability. If a test is executed on a Simulator then UI language is changed as well. You can also change Simulator language in runtime using [mobile: configureLocalization](./execute-methods.md#mobile-configurelocalization) extension. |","metadata":{"headerPath":"### App","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### App\n\n| `appium:locale` | Locale to set for iOS app, for example `fr_CA`. Please read [Locale IDs](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html#//apple_ref/doc/uid/10000171i-CH15-SW9) to get more details about available values for this capability. If a test is executed on a Simulator then UI locale is changed as well. You can also change Simulator locale in runtime using [mobile: configureLocalization](./execute-methods.md#mobile-configurelocalization) extension. |\n| `appium:calendarFormat` | Calendar format to set for iOS Simulator, for example `gregorian` or `persian`. Can only be set in conjunction with `appium:locale`. |\n| `appium:appPushTimeout` | The timeout for an application install/upgrade in milliseconds. Works for real devices only. The default value is `480000` ms (8 minutes) |\n| **Deprecated** **Not used since v7.15.0** `appium:appInstallStrategy` | Select application installation strategy for real devices. The following strategies are supported:<br>`serial` (default) - pushes app files to the device in a sequential order; this is the least performant strategy, although the most reliable<br>`parallel` - pushes app files simultaneously; this is usually the the most performant strategy, but sometimes could not be very stable<br>`ios-deploy` - tells the driver to use a third-party tool [ios-deploy](https://www.npmjs.com/package/ios-deploy) to install the app; obviously the tool must be installed separately first and must be present in PATH before it could be used. |\n| `appium:appTimeZone` | Defines the custom time zone override for the application under test. You can use UTC, PST, EST, as well as place-based timezone names such as America/Los_Angeles. The application must be (re)launched for the capability to take effect. See the [List of tz database time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for more details. The same behavior could be achieved by providing a custom value to the [TZ](https://developer.apple.com/forums/thread/86951#263395) environment variable via the `appium:processArguments` capability | UTC |","metadata":{"headerPath":"### App","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### WebDriverAgent\n\n|<div style=\"width:10em\">Capability</div>|Description|<div style=\"width:6em\">Example</div>|\n|----------|-----------|------|\n|`appium:xcodeOrgId`|Apple developer team identifier string. Must be used in conjunction with `xcodeSigningId` to take effect.|`JWL241K123`|\n|`appium:xcodeSigningId`|String representing a signing certificate. Must be used in conjunction with `xcodeOrgId`. This is usually just `Apple Development` or `iPhone Developer`, so the default (if not included) is `iPhone Developer`|`Apple Developer`|\n|`appium:xcodeConfigFile`|Full path to an optional Xcode configuration file that specifies the code signing identity and team for running the `WebDriverAgent` on the real device.|`/path/to/myconfig.xcconfig`|\n|`appium:updatedWDABundleId`|Bundle id to update WDA to before building and launching it. This bundle id _must_ be associated with a valid provisioning profile. The default value is `com.facebook.WebDriverAgentRunner`. |`io.appium.WebDriverAgentRunner`|\n|`appium:keychainPath`|Full path to the private development key exported from the system keychain. Used in conjunction with `keychainPassword` when testing on real devices.|`/path/to/MyPrivateKey.p12`|\n|`appium:keychainPassword`|Password for unlocking keychain specified in `keychainPath`.|`super awesome password`|\n|`appium:derivedDataPath`|Overrides the folder that should be used for derived data when performing a source building with xCode. xCode stores all build and test artifacts under this file system root. Use this capability to set a unique path while running [parallel tests](../guides/parallel-tests.md) or to have more control over built artifacts, for example if you'd like to use [preinstalled](../guides/run-preinstalled-wda.md) or [prebuilt](../guides/run-prebuilt-wda.md) WDA to reduce the session startup time. If the capability is not set then Xcode will store the derived data in the default root taken from preferences (usually a subfolder of `/Users/<username>/Library/Developer/Xcode/DerivedData`).|`/tmp/wda-861563ec`|\n|`appium:webDriverAgentUrl`|If provided, Appium will connect to an existing `WebDriverAgent` instance at this URL instead of starting a new one.|`http://localhost:8100`|","metadata":{"headerPath":"### WebDriverAgent","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### WebDriverAgent\n\n|`appium:webDriverAgentUrl`|If provided, Appium will connect to an existing `WebDriverAgent` instance at this URL instead of starting a new one.|`http://localhost:8100`|\n|`appium:useNewWDA`|If `true`, forces uninstall of any existing `WebDriverAgent` app on device. Set it to `true` if you want to apply different startup options for `WebDriverAgent` for each session. Although, it is only guaranteed to work stable on Simulator. Real devices require `WebDriverAgent` client to run for as long as possible without reinstall/restart to avoid issues like https://github.com/facebook/WebDriverAgent/issues/507. The `false` value (the default behaviour since driver version 2.35.0) will try to detect currently running WDA listener executed by previous testing session(s) and reuse it if possible, which is highly recommended for real device testing and to speed up suites of multiple tests in general. A new WDA session will be triggered at the default URL (http://localhost:8100) if WDA is not listening and `webDriverAgentUrl` capability is not set. The negative/unset value of `useNewWDA` capability has no effect prior to xcuitest driver version 2.35.0.|`true`|\n|`appium:wdaLaunchTimeout`|Time, in ms, to wait for `WebDriverAgent` to be pingable. Defaults to 60000ms.|`30000`|\n|`appium:wdaConnectionTimeout`|Timeout, in ms, for waiting for a response from `WebDriverAgent`. Defaults to 240000ms.|`1000`|\n|`appium:wdaStartupRetries`|Number of times to try to build and launch `WebDriverAgent` onto the device by `xcodebuild`. It does not work for `webDriverAgentUrl` and `usePreinstalledWDA` capabilities since they handle `WebDriverAgent` without the `xcodebuild`. Defaults to 2 for simulators and 1 for real devices. |`4`|\n|`appium:wdaStartupRetryInterval`|Time, in ms, to wait between tries to build and launch `WebDriverAgent`. Defaults to 10000ms.|`20000`|\n|`appium:wdaLocalPort`|This value if specified, will be used to forward traffic from Mac host to real ios devices over USB. Default value is same as port number used by WDA on device.|`8100`|\n|`appium:wdaRemotePort`|This value if specified, will be used as the port number to start WDA HTTP server on the remote device. This is only relevant for real devices, because Simulator shares ports with its host. If `webDriverAgentUrl` is provided then it might be used to provide a hint for the remote port number if it differs from the default one. Default value is 8100.|`8100`|","metadata":{"headerPath":"### WebDriverAgent","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### WebDriverAgent\n\n|`appium:wdaBindingIP`|This value if specified, will be used as the IP address for WDA HTTP server to bind on the remote device. This is only relevant for simulators, because the custom IP needs to be registered with OS and that's available only on macOS. |`127.0.0.1`|\n|`appium:wdaBaseUrl`| This value if specified, will be used as a prefix to build a custom `WebDriverAgent` url. It is different from `webDriverAgentUrl`, because if the latter is set then it expects `WebDriverAgent` to be already listening and skips the building phase. Defaults to `http://localhost` | `http://192.168.1.100`|\n|`appium:showXcodeLog`|Whether to display the output of the Xcode command used to run the tests. If this is `true`, there will be **lots** of extra logging at startup. Defaults to `false`|`true`|\n|`appium:iosInstallPause`|Time in milliseconds to pause between installing the application and starting `WebDriverAgent` on the device. Used particularly for larger applications. Defaults to `0`|`8000`|\n|`appium:prebuildWDA`|Enables prebuilding if the WebDriverAgentRunner application before running the WDA app. With this capability, XCUITest driver builds the WDA project first, then it handles the session as `appium:usePrebuiltWDA` `true` behavior. Defaults to `false`.|`true`|\n|`appium:usePrebuiltWDA`|Skips the build phase of running the WDA app. Building is then the responsibility of the user. `appium:derivedDataPath` let the session use the path as `-derivedDataPath` argument for `xcodebuild` command. Defaults to `false`.|`true`|\n|`appium:prebuiltWDAPath`| The full path to the prebuilt WebDriverAgent-Runner application package to be installed if `appium:usePreinstalledWDA` capability is enabled. The package's bundle identifier could be customized via `appium:updatedWDABundleId` capability. |`/path/to/WebDriverAgentRunner-Runner.app`|","metadata":{"headerPath":"### WebDriverAgent","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### WebDriverAgent\n\n|`appium:usePreinstalledWDA`| Whether to launch a preinstalled WebDriverAgentRunner application using a custom XCTest API client (via `com.apple.instruments` service) instead of running `xcodebuild` for real devices or simulators via simctl tool (since driver version 7.4.0). If `appium:prebuiltWDAPath` is provided, XCUITest driver will install WebDriverAgent-Runner app from the given path before launching the application. The preinstalled WebDriverAgent package must be built by Xcode 12+. The default target bundle identifier is `com.facebook.WebDriverAgentRunner.xctrunner`, although it could be customized by providing the `appium:updatedWDABundleId` capability value (the `.xctrunner` suffix is added automatically). Please read [Run Preinstalled WebDriverAgentRunner](../guides/run-preinstalled-wda.md) for more details. Defaults to `false`. |`true` or `false`|\n|`appium:updatedWDABundleIdSuffix`| Add suffix for the bundle id provided by the `appium:updatedWDABundleId` capability value in `appium:usePreinstalledWDA` capability usage since XCUITest driver v7.6.0. This is for an advanced usage that sets an arbitrary `CFBundleIdentifier` for prebuilt WebDriverAgent package to sign with the bundle identifier's certificate. For example, if you would need to sign a WebDriverAgent package with `io.appium.wda` bundle identifier's certificate, the WebDriverAgent's package must have the same bundle identifier as `CFBundleIdentifier`. Then, the WebDriverAgent package can be launched by `io.appium.wda`, which does not have `.xctrunner`. Then `\"appium:updatedWDABundleIdSuffix\": \"\"` (an empty string) helps. Please read [Run Preinstalled WebDriverAgentRunner](../guides/run-preinstalled-wda.md) for more details. Defaults to `.xctrunner`. | `\"\"`, `\".customsuffix\"` |\n|`appium:shouldUseSingletonTestManager`|Use default proxy for test management within `WebDriverAgent`. Setting this to `false` sometimes helps with socket hangup problems. Defaults to `true`.|`false`|\n|`appium:waitForIdleTimeout`|The amount of time in float seconds to wait until the application under test is idling. XCTest requires the app's main thread to be idling in order to execute any action on it, so WDA might not even start/freeze if the app under test is constantly hogging the main thread. The default value is `10` (seconds). Setting it to zero disables idling checks completely (not recommended) and has the same effect as setting `waitForQuiescence` to `false`. Available since Appium 1.20.0. |`1`|","metadata":{"headerPath":"### WebDriverAgent","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### WebDriverAgent\n\n|`appium:useXctestrunFile`|Use Xctestrun file to launch WDA. It will search for such file in `bootstrapPath`. Expected name of file is `WebDriverAgentRunner_iphoneos<sdkVersion>-arm64.xctestrun` for real device and `WebDriverAgentRunner_iphonesimulator<sdkVersion>-x86_64.xctestrun` for simulator. One can do `build-for-testing` for `WebDriverAgent` project for simulator and real device and then you will see [Product Folder like this](./assets/images/useXctestrunFile.png) and you need to copy content of this folder at `bootstrapPath` location. Since this capability expects that you have already built `WDA` project, it neither checks whether you have necessary dependencies to build `WDA` nor will it try to build project. Defaults to `false`. _Tips: `Xcodebuild` builds for the target platform version. We'd recommend you to build with minimal OS version which you'd like to run as the original WDA module. e.g. If you build WDA for 12.2, the module cannot run on iOS 11.4 because of loading some module error on simulator. A module built with 11.4 can work on iOS 12.2. (This is xcodebuild's expected behaviour.)_ |`true`|\n| **Deprecated** `appium:useSimpleBuildTest`| Build with `build` and run test with `test` in xcodebuild for all Xcode version if this is `true`, or build with `build-for-testing` and run tests with `test-without-building` for over Xcode 8 if this is `false`. Defaults to `false`. | `true` or `false` |\n|`appium:wdaEventloopIdleDelay`|Delays the invocation of `-[XCUIApplicationProcess setEventLoopHasIdled:]` by the number of seconds specified with this capability. This can help quiescence apps that fail to do so for no obvious reason (and creating a session fails for that reason). This increases the time for session creation because `-[XCUIApplicationProcess setEventLoopHasIdled:]` is called multiple times. If you enable this capability start with at least `3` seconds and try increasing it, if creating the session still fails. Defaults to `0`. |`5`|\n|`appium:processArguments`|Process arguments and environment which will be sent to the `WebDriverAgent` server in a new session request. Please use [mobile: launchApp](./execute-methods.md#mobile-launchapp) to launch an application with process arguments in the middle of a session. |`{ args: [\"a\", \"b\", \"c\"] , env: { \"a\": \"b\", \"c\": \"d\" } }` or `'{\"args\": [\"a\", \"b\", \"c\"], \"env\": { \"a\": \"b\", \"c\": \"d\" }}'`|","metadata":{"headerPath":"### WebDriverAgent","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### WebDriverAgent\n\n|`appium:autoLaunch`|When set to `false`, prevents the application under test from being launched automatically as a part of the new session startup process. The launch become the responsibility of the user. Defaults to `true`.|`true` or `false`|\n|`appium:allowProvisioningDeviceRegistration`|Allow `xcodebuild` to register your destination device on the developer portal if necessary. Requires a developer account to have been added in Xcode's Accounts preference pane. Defaults to `false`.|`true` or `false`|\n|`appium:resultBundlePath`| Specify the path to the result bundle path as `xcodebuild` argument for `WebDriverAgent` build under a security flag (Please check _Opt-in Features_ section below). `WebDriverAgent` process must start/stop every time to pick up changed value of this property. Specifying `useNewWDA` to `true` may help there. Please read `man xcodebuild` for more details. | `/path/to/resultbundle` |\n|`appium:resultBundleVersion`| Specify the version of result bundle as `xcodebuild` argument for `WebDriverAgent` build. The default value depends on your Xcode version. Please read `man xcodebuild` for more details. | `/path/to/resultbundle` |\n|`appium:maxTypingFrequency`|Maximum frequency of keystrokes for typing and clear. If your tests are failing because of typing errors, you may want to adjust this. Defaults to 60 keystrokes per minute.|`30`|\n|`appium:simpleIsVisibleCheck`|Use native methods for determining visibility of elements. In some cases this takes a long time. Setting this capability to `false` will cause the system to use the position and size of elements to make sure they are visible on the screen. This can, however, lead to false results in some situations. Defaults to `false`. | `true`, `false`|\n| **Deprecated** `appium:waitForQuiescence`| It allows to turn on/off waiting for application quiescence in `WebDriverAgent`, while performing queries. The default value is `true`. You can avoid [this kind of issues](https://github.com/appium/appium/issues/11132) if you turn it off. Consider using `waitForIdleTimeout` capability instead for this purpose since Appium 1.20.0 | `false` |\n|`appium:mjpegServerPort`|The port number on which WDA broadcasts screenshots stream encoded into MJPEG format from the device under test. It might be necessary to change this value if the default port is busy because of other tests running in parallel. Default value: `9100`|`12000`|","metadata":{"headerPath":"### WebDriverAgent","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### WebDriverAgent\n\n|`appium:mjpegScreenshotUrl` | The URL of a service that provides realtime device screenshots in MJPEG format. If provided then the actual command to retrieve a screenshot will be requesting pictures from this service rather than directly from the server. Appium does not handle port forward etc to the URL. | `http://<ip address to the device>:9100` |\n|`appium:screenshotQuality`| Changes the initial quality of display screenshots. This capability affects the screenshoting speed and the actual quality of resulting screenshots. Before version 5.4.0 of WebDriverAgent possible values were: `0`, `1` (default), `2`, where `0` abbreviates lossless PNG, `1` is a high-quality JPEG and `2` is a low-quality JPEG. In the version 5.4.0 one more mode has been added (`3`), which is now the default one. It abbreviates lossless HEIC with fallback to PNG if the device does not support hardware-accelerated HEIC encoding. You can also change the value of screenshotQuality in [settings](settings.md). | `2` |\n|`appium:autoAcceptAlerts`| Accept all iOS alerts automatically if they pop up. This includes privacy access permission alerts (location, contacts, photos). Default is `false`. |`true` or `false`|\n|`appium:autoDismissAlerts`| Dismiss all iOS alerts automatically if they pop up. This includes privacy access permission alerts (location, contacts, photos). Default is `false`. |`true` or `false`|\n|`appium:disableAutomaticScreenshots`| Disable automatic screenshots taken by XCTest at every interaction. Default is up to `WebDriverAgent`'s config to decide, which currently defaults to `true`. |`true` or `false`|\n|`appium:shouldTerminateApp`| Specify if the app should be terminated on session end. This capability only has an effect if an application identifier has been passed to the test session (either explicitly, by setting bundleId, or implicitly, by providing app). Default is `true` unless `noReset` capability is set to `true`. |`true` or `false`|\n|`appium:forceAppLaunch`| Specify if the app should be forcefully restarted if it is already running on session startup. This capability only has an effect if an application identifier has been passed to the test session (either explicitly, by setting bundleId, or implicitly, by providing app). Default is `true` unless `noReset` capability is set to `true`. |`true` or `false`|","metadata":{"headerPath":"### WebDriverAgent","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### WebDriverAgent\n\n|`appium:useNativeCachingStrategy`| Set this capability to `false` in order to use the custom elements caching strategy. This might help to avoid stale element exception on property change. By default the native XCTest cache resolution is used (`true`) for all native locators (e.g. all, but xpath). Check the corresponding [WebDriverAgent pull request](https://github.com/appium/WebDriverAgent/pull/516) for more details. |`true` or `false`|\n|`appium:appLaunchStateTimeoutSec`|Allows to set the timeout in float seconds for the application state change on the session startup in range (0, 240) exclusively. The default value for it in XCTest is 60 seconds, which means WDA would throw an exception if the application under test is not ready for accessibility interactions in 60s after its process has started. **Important**: The fact the application's user interface is visible does not necessarily mean it could be immediately interacted with by XCTest. The latter must ensure the app's main thread is also idling. Setting this capability to a lower value might help to avoid prolonged test startup with problematic apps taking too much time to be ready and fail fast. It is not advised to increase the capability value above 60 seconds, rather consider fixing the affected application itself. Too low values though may cause unexpected app startup failures. The capability does not have an effect if the app under test is not (re)started at the beginning of the session. | `10.5` |","metadata":{"headerPath":"### WebDriverAgent","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Simulator\n\n|<div style=\"width:10em\">Capability</div>|Description|<div style=\"width:7em\">Example</div>|\n|----------|-----------|------|\n|`appium:orientation`|Start a test session in a certain orientation. Note, that Simulator may ignore this capability if the simulated device itself does not support orientation change in its current state. For example, iPhones only allow orientation change to landscape if an app that declares landscape support in its manifest is running. Thus changing the orientation from portrait to something else being on home screen won't have any effect.|`LANDSCAPE` or `PORTRAIT`|\n|`appium:scaleFactor`|Simulator scale factor. This is useful to have if the default resolution of simulated device is greater than the actual display resolution, so you can scale the simulator to see the whole device screen without scrolling. Must be a string containing a positive float value.|`'2.0'`|\n|`appium:connectHardwareKeyboard`|Set this option to `true` in order to enable hardware keyboard in Simulator. The preference works only when XCUITest driver launches a simulator instance with this value. It is set to `false` by default, because this helps to workaround some XCTest bugs. `connectHardwareKeyboard: true` makes `forceSimulatorSoftwareKeyboardPresence: false` if no explicit value is set for `forceSimulatorSoftwareKeyboardPresence` capability since Appium 1.22.0. |`true` or `false`|\n|`appium:forceSimulatorSoftwareKeyboardPresence`|Set this option to `true` in order to turn software keyboard on and turn hardware keyboard off in Simulator since Appium 1.22.0. This option helps to avoid `Keyboard is not present` error. It is set to `true` by default. XCUITest driver respects preset simulator software/hardware keyboard preference when this value is `false`, so `connectHardwareKeyboard: false` and `forceSimulatorSoftwareKeyboardPresence: false` means for XCUITest driver to keep the current Simulator keyboard preferences. This option has priority over `connectHardwareKeyboard`. |`true` or `false`|\n|`appium:skipSyncUiDialogTranslation`|Set this option to `true` in order to skip synchronizing UI dialogs translation. While this option might leave some system UI alerts untranslated, it helps to avoid unexpected side effects (see [this issue](https://github.com/appium/appium/issues/19440) for more details). It is set to `false` by default. |`true` or `false`|","metadata":{"headerPath":"### Simulator","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Simulator\n\n| **Deprecated** `appium:calendarAccessAuthorized`|This capability is obsolete. Please use `appium:permissions` one instead with the `calendar` key.|`true` or `false`|\n|`appium:isHeadless`|Set this capability to `true` if automated tests are running on Simulator and the device display is not needed to be visible. This only has an effect since Xcode9 and only for simulators. All running instances of Simulator UI are going to be automatically terminated if headless test is started. `false` is the default value.|`true`|\n|`appium:simulatorWindowCenter`|Allows to explicitly set the coordinates of Simulator window center for Xcode9+ SDK. This capability only has an effect if Simulator window has not been opened yet for the current session before it started. Must be a tuple containing floats or integers, with no spaces.|`{-100.0,100.0}`|\n|`appium:simulatorStartupTimeout`|Allows to change the default timeout for Simulator startup. By default this value is set to 120000ms (2 minutes), although the startup could take longer on a weak hardware or if other concurrent processes use much system resources during the boot up procedure.|`300000`|\n|`appium:simulatorTracePointer`|Whether to highlight pointer moves in the Simulator window. The Simulator UI client must be shut down before the session startup in order for this capability to be applied properly. `false` by default.|`true`|\n|`appium:shutdownOtherSimulators`|If this capability set to `true` and the current device under test is an iOS Simulator then Appium will try to shutdown all the other running Simulators before to start a new session. This might be useful while executing webview tests on different devices, since only one device can be debugged remotely at once due to an Apple bug. The capability only has an effect if `--relaxed-security` command line argument is provided to the server. Defaults to `false`.|`true`|\n|`appium:enforceFreshSimulatorCreation`| Creates a new simulator in session creation and deletes it in session deletion. Defaults to `false`. | `true` or `false` |\n|`appium:keepKeyChains`|Set the capability to `true` in order to preserve Simulator keychains folder after full reset. This feature has no effect on real devices. Defaults to `false`|`true`|","metadata":{"headerPath":"### Simulator","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Simulator\n\n|`appium:keepKeyChains`|Set the capability to `true` in order to preserve Simulator keychains folder after full reset. This feature has no effect on real devices. Defaults to `false`|`true`|\n|`appium:keychainsExcludePatterns`|This capability accepts comma-separated path patterns, which are going to be excluded from keychains restore while full reset is being performed on Simulator. It might be useful if you want to exclude only particular keychain types from being restored, like the applications keychain. This feature has no effect on real devices.|`*keychain*.db*`|\n|`appium:reduceMotion`| It allows to turn on/off reduce motion accessibility preference. Setting reduceMotion `on` helps to reduce flakiness during tests. Only on simulators | `true` |\n|`appium:reduceTransparency`| It allows you to turn on/off reduce transparency accessibility preference. Setting reduceTransparency `on` helps to reduce screenshot image distortion during tests. Only on simulators | `true` |\n|`appium:autoFillPasswords`| It allows you to turn on/off autofill passwords function when text field is foccused. Works only with iOS16.4+ simulators | `true` |\n|`appium:permissions`| Allows to set permissions for the specified application bundle on Simulator only. The capability value is expected to be a valid JSON string with `{\"<bundleId1>\": {\"<serviceName1>\": \"<serviceStatus1>\", ...}, ...}` format. Since Xcode SDK 11.4 Apple provides native APIs to interact with application settings. Check the output of `xcrun simctl privacy booted` command to get the list of available permission names. Use `yes`, `no` and `unset` as values in order to `grant`, `revoke` or `reset` the corresponding permission. Below Xcode SDK 11.4 it is required that `applesimutils` package is installed and available in PATH. The list of available service names and statuses can be found at https://github.com/wix/AppleSimulatorUtils. | `{\"com.apple.mobilecal\": {\"calendar\": \"YES\"}}` |\n|`appium:iosSimulatorLogsPredicate`|Set the `--predicate` flag in the ios simulator logs|`'process != \"locationd\" AND process != \"DTServiceHub\"' AND process != \"mobileassetd\"`|\n|`appium:simulatorLogLevel`|Allows to customize the minimum log level for logs collected from simulators. Possible values are `default` (the default value), `info` and `debug`| `debug` |","metadata":{"headerPath":"### Simulator","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Simulator\n\n|`appium:simulatorLogLevel`|Allows to customize the minimum log level for logs collected from simulators. Possible values are `default` (the default value), `info` and `debug`| `debug` |\n|`appium:simulatorPasteboardAutomaticSync`| Handle the `-PasteboardAutomaticSync` flag when simulator process launches. It could improve launching simulator performance not to sync pasteboard with the system when this value is `off`. `on` forces the flag enabled. `system` does not provide the flag to the launching command. `on`, `off`, or `system` is available. They are case insensitive. Defaults to `off` | `system` |\n|`appium:simulatorDevicesSetPath`| This capability allows to set an alternative path to the simulator devices set in case you have multiple sets deployed on your local system. Such feature could be useful if you, for example, would like to save disk space on the main system volume. | `/MyVolume/Devices` |\n|`appium:safariGlobalPreferences`| Allows changing of Mobile Safari's preferences at the session startup. Check the documentation on arguments of [mobile: updateSafariPreferences](./execute-methods.md#mobile-updatesafaripreferences) extension to get more details on the value type requirements. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup for this capability to take effect on real devices. | `{ ShowTabBar: 0, WarnAboutFraudulentWebsites: 0 }` |","metadata":{"headerPath":"### Simulator","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Web Context\n\n|<div style=\"width:10em\">Capability</div>|Description|<div style=\"width:7em\">Example</div>|\n|----------|-----------|------|\n|`pageLoadStrategy` | One of the available page load strategies. See https://www.w3.org/TR/webdriver/#capabilities. Default `normal`. | `eager` |\n|`appium:absoluteWebLocations`|This capability will direct the `Get Element Location` command, when used within webviews, to return coordinates which are relative to the origin of the page, rather than relative to the current scroll offset. This capability has no effect outside of webviews. Default `false`.|`true`|\n|`appium:safariGarbageCollect`|Turns on/off Web Inspector garbage collection when executing scripts on Safari. Turning on may improve performance. Defaults to `false`.|`true` or `false`|\n|`appium:includeSafariInWebviews`|Add Safari web contexts to the list of contexts available during a native/webview app test. This is useful if the test opens Safari and needs to be able to interact with it. Defaults to `false`.|`true` or `false`|\n|`appium:safariLogAllCommunication`|Log all plists sent to and received from the Web Inspector, as plain text. For some operations this can be a lot of data, so it is recommended to be used only when necessary. Defaults to `false`.|`true` or `false`|\n|`appium:safariLogAllCommunicationHexDump`|Log all communication sent to and received from the Web Inspector, as raw hex dump and printable characters. This logging is done _before_ any data manipulation, and so can elucidate some communication issues. Like `appium:safariLogAllCommunication`, this can produce a lot of data in some cases, so it is recommended to be used only when necessary. Defaults to `false`.|`true` or `false`|\n|`appium:safariSocketChunkSize`|The size, in _bytes_, of the data to be sent to the Web Inspector on iOS 11+ real devices. Some devices hang when sending large amounts of data to the Web Inspector, and breaking them into smaller parts can be helpful in those cases. Defaults to `16384` (also the maximum possible)|`1000`|\n|`appium:safariWebInspectorMaxFrameLength`| The maximum size in bytes of a single data frame for the Web Inspector. Too high values could introduce slowness and/or memory leaks. Too low values could introduce possible buffer overflow exceptions. Defaults to 20MB (`20*1024*1024`) |`1024`, `100*1024*1024` |","metadata":{"headerPath":"### Web Context","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Web Context\n\n|`appium:additionalWebviewBundleIds`|Array (or JSON array) of possible bundle identifiers for webviews. This is sometimes necessary if the Web Inspector is found to be returning a modified bundle identifier for the app. If the value includes `*`, XCUITest driver will return all available webview contexts on the device. Defaults to `[]`|`[\"io.appium.modifiedId', 'ABCDEF\"]`, `[\"*\"]`|\n|`appium:webviewAtomWaitTimeout`|The time to wait, in `ms`, for each atom execution timeout of webviews in MobileSafari or hybrid apps. Defaults to `120000`. If the value was zero or less, the timeout keeps the default value. |`20000`|\n|`appium:safariIgnoreWebHostnames`| Provide a list of hostnames (comma-separated) that the Safari automation tools should ignore. This is to provide a workaround to prevent a webkit bug where the web context is unintentionally changed to a 3rd party website and the test gets stuck. The common culprits are search engines (yahoo, bing, google) and `about:blank` |`'www.yahoo.com, www.bing.com, www.google.com, about:blank'`|\n|`appium:nativeWebTap`| Enable native, non-javascript-based taps being in web context mode. Defaults to `false`. Warning: sometimes the preciseness of native taps could be broken, because there is no reliable way to map web element coordinates to native ones. | `true` |\n|`appium:nativeWebTapStrict`| Enabling this capability would skip the additional logic that tries to match web view elements to native ones by using their textual descriptions. Depending on the actual web view content this algorithm might sometimes be not very reliable and will slow down each click as we anyway fallback to the usual coordinates transformation flow if it fails. It is advised to enable strict tap if you use [mobile: calibrateWebToRealCoordinatesTranslation](./execute-methods.md#mobile-calibratewebtorealcoordinatestranslation) extension. Only applicable if `nativeWebTap` is enabled. `false` by default | `true` |\n|`appium:safariInitialUrl`| Initial safari url, default is a local welcome page. Setting it to an empty string will skip the initial navigation. | `https://www.github.com` |\n|`appium:safariAllowPopups`| Allow javascript to open new windows in Safari. Default keeps the current setting. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup on real devices for this capability to take effect. |`true` or `false`|","metadata":{"headerPath":"### Web Context","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Web Context\n\n|`appium:safariIgnoreFraudWarning`| Prevent Safari from showing a fraudulent website warning. Default keeps the current setting. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup on real devices for this capability to take effect. |`true` or `false`|\n|`appium:safariOpenLinksInBackground`| Whether Safari should allow links to open in new windows. Default keeps the current sim setting. Only available on real devices since driver version 7.9.0. A new Safari instance must be launched upon test startup on real devices for this capability to take effect. |`true` or `false`|\n|`appium:webviewConnectRetries`| The maximum number of retries before giving up on web view pages detection. Under the hood the remote debugger waits until webkit delivers the list of connected applications pages (`_rpc_applicationSentListing`). The delay between each retry is 500ms, which creates a minimum 10s of waiting time with the default retries amount of `20`. |`10`|\n|`appium:webviewConnectTimeout`| The time to wait, in `ms`, for the presence of webviews in MobileSafari or hybrid apps. Under the hood the remote debugger waits until webkit delivers the list of connected applications (`_rpc_reportConnectedApplicationList`) after sending a request for setting the connection key (`_rpc_reportIdentifier`). For better stability it might be necessary to increase this value if you run tests on Simulator and the host does not perform fast enough, for example in the continuous integration environment. `5000` ms by default. |`10000`|\n|`appium:enableAsyncExecuteFromHttps`| Capability to allow simulators to execute asynchronous JavaScript on pages using HTTPS. Defaults to `false` | `true` or `false` |\n|`appium:fullContextList` | Returns the detailed information on contexts for the [Get Contexts](https://appium.io/docs/en/latest/guides/context/) command. If this capability is enabled, then each item in the returned contexts list would additionally include WebView title, full URL and the bundle identifier. Defaults to `false`. | `true` or `false` |\n|`appium:enablePerformanceLogging`| Enable Safari's performance logging (default `false`)| `true`, `false`|\n|`appium:autoWebview`| Move directly into Webview context if available. Default `false`|`true`, `false`|","metadata":{"headerPath":"### Web Context","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Web Context\n\n|`appium:autoWebview`| Move directly into Webview context if available. Default `false`|`true`, `false`|\n|`appium:skipTriggerInputEventAfterSendkeys`| If this capability is set to `true`, then whenever you call the Send Keys method in a web context, the driver will not fire an additional `input` event on the input field used for the call. This event, turned on by default, helps in situations where JS frameworks (like React) do not respond to the input events that occur by default when the underlying Selenium atom is executed. Default `false`|`true`, `false`|\n|`appium:sendKeyStrategy`| If this capability is set to `oneByOne`, then whenever you call the Send Keys method in a web context, the driver will type each character the given string consists of in serial order to the element. This strategy helps in situations where JS frameworks (like React) update the view for each input. If `appium:skipTriggerInputEventAfterSendkeys` capability is `true`, it will affect every type. For example, when you are going to type the word `appium` with `oneByOne` strategy and `appium:skipTriggerInputEventAfterSendkeys` is enabled, the `appium:skipTriggerInputEventAfterSendkeys` option affects each typing action: `a`, `p`, `p`,`i`, `u` and `m`. Suppose any other value or no value has been provided to the `appium:sendKeyStrategy` capability. In that case, the driver types the given string in the destination input element. `appium` Send Keys input types `appium` if `oneByOne` was not set. |`oneByOne`|\n|`appium:showSafariConsoleLog`| Adds Safari JavaScript console events to Appium server logs (`true`) and writes fully serialized events into the `safariConsole` logs bucket (both `true` and `false`). If unset then no console events are being collected, which helps to save CPU and memory resources. Before the driver version 7.22 the default behavior was to always collect console logs if the capability is not set. Setting the value to `false` mimics that legacy behavior. |`true`, `false`|\n|`appium:showSafariNetworkLog`| Adds Safari network events to Appium server logs (`true`) and writes fully serialized events into the `safariNetwork` logs bucket (both `true` and `false`). If unset then no network events are being collected, which helps to save CPU and memory resources. Before the driver version 7.22 the default behavior was to always collect network logs if the capability is not set. Setting the value to `false` mimics that legacy behavior. |`true`, `false`|","metadata":{"headerPath":"### Web Context","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Other\n\n|<div style=\"width:10em\">Capability</div>|Description|<div style=\"width:6em\">Example</div>|\n|----------|-----------|------|\n|`appium:resetOnSessionStartOnly`|Whether to perform reset on test session finish (`false`) or not (`true`). Keeping this variable set to `true` and Simulator running (the default behaviour since version 1.6.4) may significantly shorten the duration of test session initialization. Defaults to `true`|`true` or `false`|\n|`appium:commandTimeouts`|Custom timeout(s) in milliseconds for WDA backend commands execution. This might be useful if WDA backend freezes unexpectedly or requires too much time to fail and blocks automated test execution. The value is expected to be of type string and can either contain max milliseconds to wait for each WDA command to be executed before terminating the session forcefully or a valid JSON string, where keys are internal Appium command names (you can find these in logs, look for \"Executing command 'command_name'\" records) and values are timeouts in milliseconds. You can also set the 'default' key to assign the timeout for all other commands not explicitly enumerated as JSON keys.|`'120000'`, `'{\"findElement\": 40000, \"findElements\": 40000, \"setValue\": 20000, \"default\": 120000}'`|\n|`appium:useJSONSource`|Get JSON source from WDA and transform it to XML on the Appium server side. Defaults to `false`.|`true`|\n|`appium:skipLogCapture`|Skips to start capturing logs such as crash, system, safari console and safari network. It might improve performance such as network. Log related commands will not work. Defaults to `false`. |`true` or `false`|\n| **Deprecated for removal** `appium:launchWithIDB`| Launch WebDriverAgentRunner with [idb](https://github.com/facebook/idb) instead of xcodebuild. This could save a significant amount of time by skipping the xcodebuild process, although the idb might not be very reliable, especially with fresh Xcode SDKs. Check the [idb repository](https://github.com/facebook/idb/issues) for more details on possible compatibility issues. Defaults to `false`. Consider using `appium:usePreinstalledWDA`/`appium:prebuiltWDAPath` capabilities instead. |`true` or `false`|\n|`appium:showIOSLog`| Whether to show any logs captured from a device in the appium logs. Default `false`|`true` or `false`|","metadata":{"headerPath":"### Other","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"### Other\n\n|`appium:showIOSLog`| Whether to show any logs captured from a device in the appium logs. Default `false`|`true` or `false`|\n|`appium:iosSyslogFile`| A file path that points to where you want the iOS Syslogs to be written to. When setting `appium:showIOSLog` to `true`, and providing a file path, it will write to the specifed path instead of the appium log. `string`\n|`appium:clearSystemFiles`|Whether to clean temporary XCTest files (for example logs) when a testing session is closed. `false` by default| `true` or `false`\n|`appium:newCommandTimeout`|How long (in seconds) the driver should wait for a new command from the client before assuming the client has stopped sending requests. After the timeout the session is going to be deleted. `60` seconds by default. Setting it to zero disables the timer. |`100`|","metadata":{"headerPath":"### Other","sectionCount":1,"recursiveSplit":true,"filename":"capabilities.md","relativePath":"appium-xcuitest-driver/docs/reference/capabilities.md"}},{"pageContent":"---\ntitle: Commands\n---\n\nThe driver comes with a set of many available commands, in addition to the commands included in the\nAppium base driver. Refer to the documentation of your Appium client for the exact syntax to call\nthese commands.\n\nPlease note that most of the driver-specific functionality is available using\n[Execute Methods](./execute-methods.md) instead.\n\n!!! info\n\n Check the [Appium base driver documentation](https://appium.io/docs/en/latest/reference/commands/base-driver/)\n for commands inherited by the XCUITest driver\n\n### `getClipboard`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: getClipboard`](./execute-methods.md#mobile-getclipboard) extension instead\n\n`POST` **`/session/:sessionId/appium/device/get_clipboard`**\n\nGets the content of the primary clipboard on the device under test.\nSee [Get/Set Clipboard](../guides/clipboard.md) for more details\n\n### `getClipboard` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `contentType?` | `any` |\n\n### `getClipboard` > #### Returned Result\n\n`string`\n\nThe actual clipboard content encoded into base64 string. An empty string is returned if the\nclipboard contains no data.\n\n### `setClipboard`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: setClipboard`](./execute-methods.md#mobile-setclipboard) extension instead\n\n`POST` **`/session/:sessionId/appium/device/set_clipboard`**\n\nSets the primary clipboard's content on the device under test.\nSee [Get/Set Clipboard](../guides/clipboard.md) for more details\n\n### `setClipboard` > #### Arguments\n\n| Name | Type | Description |\n| :------ | :------ | :------ |\n| `content` | `any` | - |\n| `contentType?` | `any` | - |\n| `label?` | `string` | The content to be set as base64 encoded string. |\n\n### `setClipboard` > #### Returned Result\n\n``null``","metadata":{"headerPath":"","sectionCount":7,"filename":"commands.md","relativePath":"appium-xcuitest-driver/docs/reference/commands.md"}},{"pageContent":"### `getGeoLocation`\n\n`GET` **`/session/:sessionId/location`**\n\nReturns the location of the device under test. Location Services for WebDriverAgent must be set to\n'Always' to get the location data correctly.\n\nThe 'latitude', 'longitude' and 'altitude' could be zero even if the Location Services are set to\n'Always', because the device may need some time to update the location data.\n\nFor iOS 17+ simulators and real devices, this method will return the result of\n[`mobile: getSimulatedLocation`](./execute-methods.md#mobile-getsimulatedlocation) extension\nif the simulated location was previously set by [`mobile: setSimulatedLocation`](./execute-methods.md#mobile-setsimulatedlocation).\n\n**`Throws`**\n\nIf the device under test returns an error message. i.e.: tvOS returns unsupported error\n\n### `getGeoLocation` > #### Returned Result\n\n`Promise`<`altitude`: `number`, `latitude`: `number`, `longitude`: `number`\\>\n\n### `setGeoLocation`\n\n`POST` **`/session/:sessionId/location`**\n\nSet location of the device under test.\n\nFor iOS 17+ real devices, this method will call the\n[`mobile: setSimulatedLocation`](./execute-methods.md#mobile-setsimulatedlocation) extension.\n\n### `setGeoLocation` > #### Arguments\n\n| Name | Type | Description |\n| :------ | :------ | :------ |\n| `location` | `Location` | An object with `latitude` and `longitude` values |\n\n### `setGeoLocation` > #### Returned Result\n\n`Promise`<`altitude`: `number`, `latitude`: `number`, `longitude`: `number`\\>\n\n### `startRecordingScreen`\n\n`POST` **`/session/:sessionId/appium/start_recording_screen`**\n\nStart recording the device screen. This functionality is available in the iOS Simulator since\nXcode 9, and in real devices since iOS 11.\n\nScreen activity is recorded to an MPEG-4 file. Note that audio is not recorded with the video file.\nIf the screen recording has already been started, this command will force stop it and start a new\nrecording. The previously recorded video file will also be deleted.\n\n!!! info\n\n This command requires the `ffmpeg` utility to be installed (`brew install ffmpeg`)\n\n**`Throws`**\n\nIf the screen recording has failed to start.\n\n### `startRecordingScreen` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `options?` | `any` |\n\n### `startRecordingScreen` > #### Returned Result\n\n`string`\n\nBase64-encoded content of the recorded media file if any screen recording is currently running,\nor an empty string.","metadata":{"headerPath":"### `getGeoLocation`","sectionCount":8,"filename":"commands.md","relativePath":"appium-xcuitest-driver/docs/reference/commands.md"}},{"pageContent":"### `stopRecordingScreen`\n\n`POST` **`/session/:sessionId/appium/stop_recording_screen`**\n\nStop an ongoing screen recording and return the video. This functionality is available in the iOS\nSimulator since Xcode 9, and in real devices since iOS 11.\n\n\nIf no screen recording process is running, the command will attempt to retrieve the most recently\nrecorded file. If no previously recorded file is found, the method will return an empty string.\n\n**`Throws`**\n\nIf there was an error while getting the name of a media file, or the file content cannot be uploaded\nto the remote location.\n\n### `stopRecordingScreen` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `options?` | `any` |\n\n### `stopRecordingScreen` > #### Returned Result\n\n``null`` \\| `string`\n\nBase64-encoded content of the recorded media file if `remotePath` parameter is empty or null,\nor an empty string.\n\n### `getSize`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please refer to the [Get Element Rect][https://www.w3.org/TR/webdriver1/#dfn-get-element-rect] instead\n\n`GET` **`/session/:sessionId/element/:elementId/size`**\n\nGet the size of an element\n\n### `getSize` > #### Returned Result\n\n`Size`\n\nThe positions of the element\n\n### `submit`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please click the submit button instead\n\n`POST` **`/session/:sessionId/element/:elementId/submit`**\n\nSubmit the form an element is in\n\n### `submit` > #### Returned Result\n\n``null``\n\n### `background`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: backgroundApp`](./execute-methods.md#mobile-backgroundapp) extension instead\n\n`POST` **`/session/:sessionId/appium/app/background`**\n\nClose app (simulate device home button). It is possible to restore\nthe app after the timeout or keep it minimized based on the parameter value.\n\n### `background` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `seconds` | `any` |\n\n### `background` > #### Returned Result\n\n`unknown`\n\n### `queryAppState`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: queryAppState`](./execute-methods.md#mobile-queryappstate) extension instead\n\n`POST` **`/session/:sessionId/appium/device/app_state`**\n\nGet the running state of an app","metadata":{"headerPath":"### `stopRecordingScreen`","sectionCount":11,"filename":"commands.md","relativePath":"appium-xcuitest-driver/docs/reference/commands.md"}},{"pageContent":"### `queryAppState` > #### Returned Result\n\n`AppState`\n\nA number representing the state. `0` means not installed, `1` means not running, `2`\nmeans running in background but suspended, `3` means running in the background, and `4` means\nrunning in the foreground\n\n### `isLocked`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: isLocked`](./execute-methods.md#mobile-islocked) extension instead\n\n`POST` **`/session/:sessionId/appium/device/is_locked`**\n\nDetermine whether the device is locked\n\n### `isLocked` > #### Returned Result\n\n`boolean`\n\n`true` if the device is locked, `false` otherwise\n\n### `lock`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: lock`](./execute-methods.md#mobile-lock) extension instead\n\n`POST` **`/session/:sessionId/appium/device/lock`**\n\nLock the device (and optionally unlock the device after a certain amount of time)\n\n**`Default Value`**\n\n0\n\n### `lock` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `seconds?` | `any` |\n\n### `lock` > #### Returned Result\n\n``null``\n\n### `unlock`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: unlock`](./execute-methods.md#mobile-unlock) extension instead\n\n`POST` **`/session/:sessionId/appium/device/unlock`**\n\nUnlock the device\n\n<!-- comment source: method-signature -->\n\n### `unlock` > #### Returned Result\n\n``null``\n\n### `mobileShake`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: shake`](./execute-methods.md#mobile-shake) extension instead\n\n`POST` **`/session/:sessionId/appium/device/shake`**\n\nShake the device\n\n### `mobileShake` > #### Returned Result\n\n``null``\n\n### `getStrings`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: getAppStrings`](./execute-methods.md#mobile-getappstrings) extension instead\n\n`POST` **`/session/:sessionId/appium/app/strings`**\n\nReturn the language-specific strings for an app\n\n### `getStrings` > #### Arguments\n\n| Name | Type | Default value | Description |\n| :------ | :------ | :------ | :------ |\n| `language?` | `any` | `undefined` | - |\n| `stringFile?` | `string` | `null` | The language abbreviation to fetch app strings mapping for. If no language is provided then strings for the 'en language would be returned |\n\n### `getStrings` > #### Returned Result\n\n`StringRecord`<`string`\\>\n\nA record of localized keys to localized text","metadata":{"headerPath":"### `queryAppState` > #### Returned Result","sectionCount":13,"filename":"commands.md","relativePath":"appium-xcuitest-driver/docs/reference/commands.md"}},{"pageContent":"### `setValueImmediate`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated\n\n`POST` **`/session/:sessionId/appium/element/:elementId/value`**\n\n### `setValueImmediate` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `text` | `any` |\n\n### `setValueImmediate` > #### Returned Result\n\n``null``\n\n### `keys`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use `setValue` instead\n\n`POST` **`/session/:sessionId/keys`**\n\nSend keys to the app\n\n### `keys` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `value` | `any` |\n\n### `keys` > #### Returned Result\n\n``null``\n\n### `receiveAsyncResponse`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [Execute Async Script](https://www.w3.org/TR/webdriver1/#dfn-execute-async-script) instead\n\n`POST` **`/session/:sessionId/appium/receive_async_response`**\n\nCollect the response of an async script execution\n\n### `receiveAsyncResponse` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `response` | `any` |\n\n### `receiveAsyncResponse` > #### Returned Result\n\n``null``\n\n### `toggleEnrollTouchId`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: enrollBiometric`](./execute-methods.md#mobile-enrollbiometric) extension instead\n\n`POST` **`/session/:sessionId/appium/simulator/toggle_touch_id_enrollment`**\n\nToggle whether the device is enrolled in the touch ID program\n\n### `toggleEnrollTouchId` > #### Arguments\n\n| Name | Type | Default value |\n| :------ | :------ | :------ |\n| `enabled?` | `any` | `true` |\n\n### `toggleEnrollTouchId` > #### Returned Result\n\n``null``\n\n### `touchId`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use the [`mobile: sendBiometricMatch`](./execute-methods.md#mobile-sendbiometricmatch) extension instead\n\n`POST` **`/session/:sessionId/appium/simulator/touch_id`**\n\nTrigger a touch/fingerprint match or match failure\n\n### `touchId` > #### Arguments\n\n| Name | Type | Default value |\n| :------ | :------ | :------ |\n| `match` | `any` | `true` |\n\n### `touchId` > #### Returned Result\n\n``null``\n\n### `asyncScriptTimeout`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use `scriptTimeoutW3C` instead\n\n`POST` **`/session/:sessionId/timeouts/async_script`**\n\nAlias for XCUITestDriver.scriptTimeoutW3C.\n\n### `asyncScriptTimeout` > #### Arguments\n\n| Name | Type |\n| :------ | :------ |\n| `ms` | `any` |\n\n### `asyncScriptTimeout` > #### Returned Result\n\n``null``","metadata":{"headerPath":"### `setValueImmediate`","sectionCount":18,"filename":"commands.md","relativePath":"appium-xcuitest-driver/docs/reference/commands.md"}},{"pageContent":"### `getLocation`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use `getElementRect` instead\n\n`GET` **`/session/:sessionId/element/:elementId/location`**\n\nGet the position of an element on screen\n\n### `getLocation` > #### Returned Result\n\n`Position`\n\nThe position of the element\n\n### `getLocationInView`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use `getElementRect` instead\n\n`GET` **`/session/:sessionId/element/:elementId/location_in_view`**\n\nAlias for `getLocation`\n\n### `getLocationInView` > #### Returned Result\n\n`Position`\n\nThe position of the element\n\n### `getWindowSize`\n\n!!! warning \"Deprecated\"\n\n This method is deprecated. Please use `getElementRect` instead\n\n`GET` **`/session/:sessionId/window/:windowhandle/size`**\n\nGet the window size\n\n### `getWindowSize` > #### Returned Result\n\n`any`","metadata":{"headerPath":"### `getLocation`","sectionCount":6,"filename":"commands.md","relativePath":"appium-xcuitest-driver/docs/reference/commands.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Element Attributes\n---\n\nThe XCUITest driver supports the following element attributes:","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"element-attributes.md","relativePath":"appium-xcuitest-driver/docs/reference/element-attributes.md"}},{"pageContent":"| <div style=\"width:6em\">Name</div> | Description | <div style=\"width:8em\">Example</div> |\n| --- | --- | --- |\n| `name` | Could contain either element's [identifier](https://developer.apple.com/documentation/xctest/xcuielementattributes/1500981-identifier?language=objc) or its [label](https://developer.apple.com/documentation/xctest/xcuielementattributes/1500692-label?language=objc), depending on which one is available first. Could also be `null`. It is recommended to prefer the usage of [accessibilityIdentifier](https://developer.apple.com/documentation/uikit/uiaccessibilityidentification/1623132-accessibilityidentifier) over [accessibilityLabel](https://developer.apple.com/documentation/objectivec/nsobject/1615181-accessibilitylabel) for automation purposes, since the `identifier` property is supposed to stay constant under different locales and does not affect accessibility services such as VoiceOver. In applications written using [ReactNative](https://reactnative.dev/) framework this attribute reflects the value of the `testID` property. | `hello` |\n| `label` | Element's [label](https://developer.apple.com/documentation/xctest/xcuielementattributes/1500692-label?language=objc) value. Could be `null`. Since XCUITest driver 4.7.3 (WebDriverAgent 4.8.0), the behavior of this value was better aligned with XCTest, so it could include line breaks (`\\n`). Before this version, line breaks were replaced by spaces. | `hello`, `hello\\nworld` |\n| `type` | Element's [type](https://developer.apple.com/documentation/xctest/xcuielementattributes/1500614-elementtype?language=objc) name | `XCUIElementTypeButton` |\n| `visible` | Whether the element is visible. This value is not available in the \"vanilla\" XCTest and is read directly from the accessibility layer | `false` |\n| `focused` | Whether the element is [focused](https://developer.apple.com/documentation/xctest/xcuielementattributes/1627636-hasfocus?language=objc). Before driver version 4.25.4, this was only available for tvOS. | `true` |\n| `accessible` | Whether the element is accessible. This value is not available in the \"vanilla\" XCTest and is read directly from the accessibility layer | `true` |\n| `enabled` | Whether the element is [enabled](https://developer.apple.com/documentation/xctest/xcuielementattributes/1500330-enabled?language=objc). | `false` |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"element-attributes.md","relativePath":"appium-xcuitest-driver/docs/reference/element-attributes.md"}},{"pageContent":"| `enabled` | Whether the element is [enabled](https://developer.apple.com/documentation/xctest/xcuielementattributes/1500330-enabled?language=objc). | `false` |\n| `selected` | Whether the element is [selected](https://developer.apple.com/documentation/xctest/xcuielementattributes/1500581-selected?language=objc) | `false` |\n| `index` | Element's index in the hierarchy relatively to its parent. Only available since Appium 1.20.0. Indexing starts from `0`. | `2` |\n| `rect` | Element's rectangle. The actual data of this attribute is based on element's [frame](https://developer.apple.com/documentation/xctest/xcuielementattributes/1500911-frame?language=objc). | `{'x': 0, 'y': 0, 'width': 100, 'height': 100}` |\n| `value` | Element's value. This is a complex attribute, whose calculation algorithm depends on the actual element type. Check [WebDriverAgent sources](https://github.com/appium/WebDriverAgent/blob/master/WebDriverAgentLib/Categories/XCUIElement%2BFBWebDriverAttributes.m) to know more about how it is compiled (method `- (NSString *)wdValue`). Could be `null` | `hello` |\n| `hittable` | Whether the element is [hittable](https://developer.apple.com/documentation/xctest/xcuielement/1500561-hittable). Note that XCTest hittable requires an element to have the [isAccessibilityElement](https://developer.apple.com/documentation/objectivec/nsobject-swift.class/isaccessibilityelement) property enabled. It means if the element is on screen, but it sets [accessibilityElementsHidden](https://developer.apple.com/documentation/objectivec/nsobject-swift.class/accessibilityelementshidden) to `false`, the hittable attribute will be `false`. This attribute is not included into the XML page source due to performance reasons, although you can use it in element locators or fetch its value using [getAttribute](https://www.w3.org/TR/webdriver2/#get-element-attribute) API. | `true` |\n|`placeholderValue` | Element's [placeolderValue](https://developer.apple.com/documentation/xctest/xcuielementattributes/placeholdervalue) value. | `Placeholder text`|\n|`traits` | Element's [traits](https://developer.apple.com/documentation/uikit/uiaccessibilitytraits?language=objc) value. This attribute returns a comma-separated string of accessibility traits. This attribute is not included into the XML page source, it may only be retrieved via [getAttribute](https://www.w3.org/TR/webdriver2/#get-element-attribute) API.| `Button, Adjustable`, `Button` |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"element-attributes.md","relativePath":"appium-xcuitest-driver/docs/reference/element-attributes.md"}},{"pageContent":"| `minValue` | Element's minimum allowed value, typically for controls like sliders or progress indicators. | `0`, `0.0`, `1` |\n| `maxValue` | Element's maximum allowed value, typically for controls like sliders or progress indicators. | `100`, `1.0` |\n| `customActions` | Custom accessibility actions attached to a single accessibility element (SwiftUI: [`accessibilityAction`](https://developer.apple.com/documentation/swiftui/view/accessibilityaction(_:_:)), UIKit: [`UIAccessibilityCustomAction`](https://developer.apple.com/documentation/uikit/uiaccessibilitycustomaction)). | `Action 1,Action 2` |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"element-attributes.md","relativePath":"appium-xcuitest-driver/docs/reference/element-attributes.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Environment Variables\n---\n\nThis article describes environment variables that influence various XCUITest driver behaviors.\n\n|<div style=\"width:17em\">Variable Name</div>|Description|\n|------------|-----------|\n|`APPIUM_PREFER_SYSTEM_UNZIP`|Being set to either `0` or `false` makes the driver to use built-in Node.js unzipper rather than the system unzip utility. Mostly used for debugging purposes or troubleshooting as the system unzip utility is more performant in comparison to the built-in one.|\n|`APPIUM_XCUITEST_PREFER_DEVICECTL`|Being set to `true`, `1` or `true` makes the driver to use the devicectl Xcode utility to fetch the list of available devices UDIDs instead of the built-in usbmuxd client. Might be useful for some scenarios where the latter is unable to detect connected devices. See [PR #2194](https://github.com/appium/appium-xcuitest-driver/pull/2194) for more details.|","metadata":{"headerPath":"","sectionCount":1,"filename":"env-vars.md","relativePath":"appium-xcuitest-driver/docs/reference/env-vars.md"}},{"pageContent":"---\ntitle: Execute Methods\n---\n\nIn addition to standard W3C APIs, the driver provides many custom command extensions for executing\nplatform-specific scenarios. Use the following examples in order to invoke them from your client code:\n\n=== \"Java\"\n\n ```java\n var result = driver.executeScript(\"mobile: <methodName>\", Map.ofEntries(\n Map.entry(\"arg1\", \"value1\"),\n Map.entry(\"arg2\", \"value2\")\n // you may add more pairs if needed or skip providing the map completely\n // if all arguments are defined as optional\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const result = await driver.executeScript('mobile: <methodName>', [{\n arg1: \"value1\",\n arg2: \"value2\",\n }]);\n ```\n\n=== \"Python\"\n\n ```python\n result = driver.execute_script('mobile: <methodName>', {\n 'arg1': 'value1',\n 'arg2': 'value2',\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n result = @driver.execute_script 'mobile: <methodName>', {\n arg1: 'value1',\n arg2: 'value2',\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n object result = driver.ExecuteScript(\"mobile: <methodName>\", new Dictionary<string, object>() {\n {\"arg1\", \"value1\"},\n {\"arg2\", \"value2\"}\n }));\n ```\n\n### mobile: selectPickerWheelValue\n\nPerforms selection of the next or previous picker wheel value. This might\nbe useful if these values are populated dynamically, so you don't know which\none to select or value selection suing `sendKeys` API does not work because of an XCTest bug. The method throws an exception if it fails to change the current picker value.","metadata":{"headerPath":"","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: selectPickerWheelValue > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (`element` before version 1.22) | string | yes | PickerWheel's internal element id (as hexadecimal hash string) to perform value selection on. The element must be of type XCUIElementTypePickerWheel | abcdef12-1111-2222-3333-444444\norder | string | yes | Either `next` to select the value next to the current one from the target picker wheel or `previous` to select the previous one. | next\noffset | number | no | The value in range [0.01, 0.5]. It defines how far from picker wheel's center the click should happen. The actual distance is calculated by multiplying this value to the actual picker wheel height. Too small offset value may not change the picker wheel value and too high value may cause the wheel to switch two or more values at once. Usually the optimal value is located in range [0.15, 0.3]. `0.2` by default | 0.15\nvalue | string | no | If provided WDA will try to automatically scroll in the given direction until the actual picker value reaches the expected one or the amount of scrolling attempts is exceeded. | myvalue\nmaxAttempts | number | no | The maximum number of scrolling attempts to reach `value` before an error will be thrown. Only makes sense in combination with `value`. 25 by default | 50\n\n### mobile: sendMemoryWarning\n\nSimulates sending of Low Memory warning to the target application.\nIt might be useful to verify the\n[didReceiveMemoryWarning](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621409-didreceivememorywarning?language=objc)\nAPI in the application under test.\nThis feature only works on real devices running iOS 17+ with Xcode 15+ SDK.\nThe target application must be running while this API is called.\n\n### mobile: sendMemoryWarning > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | Bundle identifier of the app to simulate the warning for | com.great.app\n\n### mobile: alert\n\nTries to apply the given action to the currently visible alert.\n\n### mobile: alert > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\naction | string | yes | The actual action to apply. Could be either: `accept`, `dismiss` or `getButtons` | accept\nbuttonLabel | string | no | The name of the button used to perform the chosen alert action. Only makes sense if the action is `accept` or `dismiss` | Accept","metadata":{"headerPath":"### mobile: selectPickerWheelValue > #### Arguments","sectionCount":5,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: alert > #### Returned Result\n\nThe list of alert button names if the selected action is `getButtons`\n\n### mobile: setPasteboard\n\nSets the Simulator's pasteboard content to the given value. Does not work for real devices.\n\n### mobile: setPasteboard > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncontent | string | yes | The content to set | hello\nencoding | string | no | The content's encoding. `utf8` by default | ascii\n\n### mobile: getPasteboard\n\nGets the Simulator's pasteboard content. Does not work for real devices.\n\n### mobile: getPasteboard > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nencoding | string | no | The expected encoding of the returned string. `utf8` by default | ascii\n\n### mobile: getPasteboard > #### Returned Result\n\nThe pasteboard content string.\n\n### mobile: source\n\nAllows to retrieve the source tree of the current page in different representation formats.\n\n### mobile: source > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nformat | string | yes | One of possible page tree source representation formats: `xml` (the default value), `description` and `json`. The `xml` format generates the output similar to what `getPageSource` standard API returns. `description` representation is how XCTest \"sees\" the page internally and is the same string as [debugDescription](https://developer.apple.com/documentation/xctest/xcuielement/1500909-debugdescription?language=objc) API would return for the root application element. This source representation format is useful for debugging purposes and is the fastest one to fetch. `json` representation is similar to `xml`, but the tree hierarchy there is represented as JSON elements tree rather than as XML nodes. | description\nexcludedAttributes | string | no | One or more comma-separated attribute names to be excluded from the XML output, thus only makes sense if `format` is set to `xml`. It might be sometimes helpful to exclude, for example, the `visible` attribute, to significantly speed-up page source retrieval. | visible,accessible\n\n### mobile: source > #### Returned Result\n\nThe page source tree formatted according to the given format argument.","metadata":{"headerPath":"### mobile: alert > #### Returned Result","sectionCount":9,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: getContexts\n\nRetrieves the list of available contexts including the extended context information, like urls and page names. This is different from the standard `getContexts` API, because the latter only has web view names without any additional information. In situation where multiple web views are available at once the client code would have to connect to each of them in order to detect the one, which needs to be interacted with. Although, this extra effort is not needed with the information provided by this extension.\n\n### mobile: getContexts > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nwaitForWebviewMs | number | no | Tells Appium for how long (in milliseconds) to wait for web view(s) to appear. `5000`ms by default | 10000\n\n### mobile: getContexts > #### Returned Result\n\nThe list of available context objects along with their properties:\n\n- id: The identifier of the context. The native context will be 'NATIVE_APP' and the webviews will be 'WEBVIEW_xxx'\n- title: The title associated with the webview content. Could be `null`\n- url: The url associated with the webview content. Could be `null`\n\n### mobile: installApp\n\nInstalls the given application to the device under test. Make sure the application is built for a correct architecture and is signed with a proper developer signature (for real devices) prior to install it.","metadata":{"headerPath":"### mobile: getContexts","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: installApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\napp | string | yes | See the description of the `appium:app` capability | /path/to/my.app\ntimeoutMs | number | no | The maximum time to wait until app install is finished in milliseconds on real devices. If not provided then the value of `appium:appPushTimeout` capability is used. If the capability is not provided then equals to 240000ms | 500000\n**Deprecated** **Not Used since v7.15.0** strategy | string | no | One of possible app installation strategies on real devices. This argument is ignored on simulators. If not provided then the value of `appium:appInstallStrategy` is used. If the latter is also not provided then `serial` is used. See the description of `appium:appInstallStrategy` capability for more details on available values. | parallel\ncheckVersion | bool | no | If set to `true`, it will make xcuitest driver to verify whether the app version currently installed on the device under test is older than the one, which is provided as `app` value. No app install is going to happen if the candidate app has the same or older version number than the already installed copy of it. The version number used for comparison must be provided as [CFBundleVersion](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion) [Semantic Versioning](https://semver.org/)-compatible value in the application's `Info.plist`. No validation is performed and the `app` is installed if `checkVersion` was not provided or `false`, which is default behavior. | true\n\n### mobile: isAppInstalled\n\nChecks whether the given application is installed on the device under test.\n[Offloaded applications](https://discussions.apple.com/thread/254887240) are handled as not installed.\n\n### mobile: isAppInstalled > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the application to be checked | com.mycompany.myapp\n\n### mobile: isAppInstalled > #### Returned Result\n\nEither `true` or `false`\n\n### mobile: removeApp\n\nRemoves the given application from the device under test.\n[Offloaded application](https://discussions.apple.com/thread/254887240) can also be removed.\n\nFor real devices, please also check [how to explicitly clear the application local data](../guides/troubleshooting.md#leftover-application-data-on-real-devices).","metadata":{"headerPath":"### mobile: installApp > #### Arguments","sectionCount":5,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: removeApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the application to be removed | com.mycompany.myapp\n\n### mobile: removeApp > #### Returned Result\n\nEither `true` if the application was successfully uninstalled, otherwise `false`","metadata":{"headerPath":"### mobile: removeApp > #### Arguments","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: launchApp\n\nExecutes the given application on the device under test. If the application is already running then it would be activated.\nIf the application is not installed or cannot be launched then an exception is thrown.\n\nIt accepts `arguments` and `environment` to start an application with them.\n\nAs an usage example, `arguments` allow you to enforce language and locale for the application to start with.\nXCTest lets you to start an application process by specifying [Language and Locale IDs](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html) via process `arguments` with `-AppleLanguages` and `-AppleLocale`.\nCheck the [Testing Specific Languages and Regions part of the Testing Your Internationalized App](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/TestingYourInternationalApp/TestingYourInternationalApp.html) for more details.\nMake sure to terminate the application before launching it with `arguments` if it is already running.\n\n=== \"Java\"\n\n ```java\n driver.executeScript(\"mobile:launchApp\", Map.of(\n \"bundleId\", \"com.apple.Preferences\",\n \"arguments\", Arrays.asList(\"-AppleLanguages\", \"(ja)\", \"-AppleLocale\", \"ja_JP\")\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n await driver.executeScript('mobile:launchApp', [{\n bundleId: 'com.apple.Preferences',\n arguments: ['-AppleLanguages', '(ja)', '-AppleLocale', 'ja_JP']\n }]);\n ```\n\n=== \"Python\"\n\n ```python\n driver.execute_script(\"mobile:launchApp\", {\n \"bundleId\": \"com.apple.Preferences\",\n \"arguments\": [\"-AppleLanguages\", \"(ja)\", \"-AppleLocale\", \"ja_JP\"]\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n driver.execute_script \"mobile:launchApp\", {\n \"bundleId\": \"com.apple.Preferences\",\n \"arguments\": [\"-AppleLanguages\", \"(ja)\", \"-AppleLocale\", \"ja_JP\"]\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n driver.ExecuteScript(\"mobile:launchApp\", new Dictionary<string, object>() {\n {\"bundleId\", \"com.apple.Preferences\"},\n {\"arguments\", new List<string>() { \"-AppleLanguages\", \"(ja)\", \"-AppleLocale\", \"ja_JP\" }}\n });\n ```","metadata":{"headerPath":"### mobile: launchApp","sectionCount":1,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: launchApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the application to be launched | com.mycompany.myapp\narguments | string&#124;array | no | One or more command line arguments for the app. If the app is already running then this argument is ignored. | ['-s', '-m']\nenvironment | dict | no | Environment variables mapping for the app. If the app is already running then this argument is ignored. | {'var': 'value'}\n\n### mobile: terminateApp\n\nTerminates the given app on the device under test via [XCTest's terminate](https://developer.apple.com/documentation/xctest/xcuiapplication/1500637-terminate) API. If the app is not installed an exception is thrown. If the app is not running then nothing is done.\n\n### mobile: terminateApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the application to be terminated | com.mycompany.myapp\n\n### mobile: terminateApp > #### Returned Result\n\nEither `true` if the app was successfully terminated, otherwise `false`\n\n### mobile: killApp\n\nKill the given app on the real device under test by instruments service.\nIf the app is not running or failed to kill, then nothing is done.\n\nXCUITest driver 4.4 and higher does not require [py-ios-device](https://github.com/YueChen-C/py-ios-device).\nXCUITest driver 4.3 requires [py-ios-device](https://github.com/YueChen-C/py-ios-device).\n\n### mobile: killApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the application to be terminated | com.mycompany.myapp\n\n### mobile: killApp > #### Returned Result\n\nEither `true` if the app was successfully killed, otherwise `false`\n\n### mobile: queryAppState\n\nQueries the state of an installed application from the device under test. An exception will be thrown if the app with given identifier is not installed.\n\n### mobile: queryAppState > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the application to be queried | com.mycompany.myapp","metadata":{"headerPath":"### mobile: launchApp > #### Arguments","sectionCount":9,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: queryAppState > #### Returned Result\n\nAn integer number is returned, which encodes the application state. Possible values are described in [XCUIApplicationState](https://developer.apple.com/documentation/xctest/xcuiapplicationstate?language=objc) XCTest documentation topic.\n\n### mobile: activateApp\n\nPuts the given application to foreground if it is running in the background. An error is thrown if the app is not installed or is not running. Nothing is done if the app is already running in the foreground.\n\n### mobile: activateApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the application to be activated | com.mycompany.myapp\n\n### mobile: listApps\n\nList applications installed on the real device under test. This extension throws an error if called\nfor a Simulator device.\nOffload applications will not be in the result.\n\n### mobile: listApps > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\napplicationType | string | no | The type of applications to list. Either `System` or `User` (the default one) | System\nreturnAttributes | array&lt;string&gt; | no | Array of attribute names to return for each app. If not provided, all available attributes are returned. Common attributes include: `CFBundleIdentifier`, `CFBundleName`, `CFBundleDisplayName`, `CFBundleVersion`, `CFBundleShortVersionString`, `UIFileSharingEnabled` | `['CFBundleIdentifier', 'CFBundleName', 'CFBundleVersion']`\n\n### mobile: listApps > #### Returned Result\n\nA map where keys are bundle identifiers and values are maps of platform-specific app properties. The properties included depend on the `returnAttributes` parameter. Having `UIFileSharingEnabled` set to `true` in the app properties map means this app supports file upload and download into its `documents` container. Read the [File Transfer](../guides/file-transfer.md) guide for more details.","metadata":{"headerPath":"### mobile: queryAppState > #### Returned Result","sectionCount":6,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: clearApp\n\nDeletes data files from the data container of an installed app,\nso it could start from the clean state next time it is launched.\nThe destination app will be terminated if it is running when this API is invoked.\nSometimes it might also be necessary to invoke the following APIs\nto fully reset the state of an installed app (make sure the app is not running while\ncalling them):\n- [mobile: clearKeychains](#mobile-clearkeychains)\n- [mobile: resetPermission](#mobile-resetpermission)\n\nThis API might not be 100% reliable for some apps. The only reliable method to fully\nreset an existing app that Apple supports is to [uninstall](#mobile-removeapp) it and then perform a fresh [install](#mobile-installapp) of the same app.\n\nThis API only works on simulators. An exception is thrown if executed with real devices.\n\n### mobile: clearApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the application to be cleared | com.mycompany.myapp\n\n### mobile: clearApp > #### Returned Result\n\n`true` if at least one item has been successfully deleted from the app data container.\n\n### mobile: startPerfRecord\n\nStarts performance profiling for the device under test.\nRelaxing security is mandatory for simulators. It can always work for real devices.\nSince XCode 12 the method tries to use `xctrace` tool to record performance stats.\nThe `instruments` developer utility is used as a fallback for this purpose if `xctrace` is not available. It is possible to record multiple profiles at the same time. Read [Instruments User Guide](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Recording,Pausing,andStoppingTraces.html) for more details.\nIf the recording for the given profile is already running then nothing is done.","metadata":{"headerPath":"### mobile: clearApp","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: startPerfRecord > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntimeout | number | no | The maximum count of milliseconds to record the profiling information. It is recommended to always limit the maximum duration of perf record operation, since the resulting logs are pretty huge and may easily exceed the free space on th local storage volume. `300000`ms by default (5 minutes) | `600000`\nprofileName | string | no | The name of existing performance profile to apply. Can also contain the full path to the chosen template on the server file system. Note, that not all profiles are supported on mobile devices. `Activity Monitor` by default. | `Time Profile`\npid | string or number | no | The ID of the process to measure the performance for. Set it to `current` in order to measure the performance of the process, which belongs to the currently active application. All processes running on the device are measured if pid is unset (the default setting). | current\n\n### mobile: stopPerfRecord\n\nStops the performance recording operation previously started by `mobile: startPerfRecord` call. If the previous call has already been completed due to the timeout then its result is returned immediately. An error is thrown if the performance recording has failed to start and recorded no data.","metadata":{"headerPath":"### mobile: startPerfRecord > #### Arguments","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: stopPerfRecord > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nprofileName | string | no | The name of existing performance profile to stop the recording for. Multiple recorders for different profile names could be executed at the same time. `Activity Monitor` by default. | `Time Profile`\nremotePath | string | no | The path to the remote location, where the resulting zipped .trace file should be uploaded. The following protocols are supported: http/https, ftp Null or empty string value (the default setting) means the content of resulting file should be zipped, encoded as Base64 and passed as the endpoint response value. An exception will be thrown if the generated file is too big to fit into the available process memory. | https://myserver/upload\nuser | string | no | The name of the user for the remote authentication. Only works if `remotePath` is provided. | myuser\npass | string | no | The password for the remote authentication. Only works if `remotePath` is provided. | mypassword\nmethod | string | no | The http multipart upload method name. Only works if `remotePath` is provided. `PUT` by default | POST\nheaders | dict | no | Additional headers mapping for multipart http(s) uploads | {'User-Agent': 'Myserver 1.0'}\nfileFieldName | string | no | The name of the form field, where the file content BLOB should be stored for http(s) uploads. `file` by default | payload\nformFields | dict or array | no | Additional form fields for multipart http(s) uploads | {'field2': 'value2'}\n\n### mobile: stopPerfRecord > #### Returned Result\n\nThe resulting file in .trace format can be either returned directly as base64-encoded zip archive or uploaded to a remote location (such files could be pretty large), depending on the `remotePath` argument value. Afterwards it is possible to unarchive and open such file with Xcode Developer Tools.","metadata":{"headerPath":"### mobile: stopPerfRecord > #### Arguments","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: installCertificate\n\nInstalls a custom certificate onto the device. Since Xcode SDK 11.4 Apple has added a dedicated simctl subcommand to quickly handle certificates on Simulator over CLI.\nOn real devices the certificate could be installed via CLI if [py-ios-device](https://github.com/YueChen-C/py-ios-device) tool is available on the server machine.\nOn simulators before Xcode 11.4 SDK Apple provides no official way to do it via the command line. In such case (and also as a fallback if CLI setup fails) this method tries to wrap the certificate into .mobileconfig format and then deploys the wrapped file to the internal HTTP server, so one can open it via mobile Safari. Then the algorithm goes through the profile installation procedure by clicking the necessary buttons using WebDriverAgent.\n\n### mobile: installCertificate > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncontent | string | yes | Base64-encoded content of the public certificate in [PEM](https://knowledge.digicert.com/quovadis/ssl-certificates/ssl-general-topics/what-is-pem-format.html) format | a23234...\ncommonName | string | no | Common name of the certificate. If this is not set then the script will try to parse it from the given certificate content. | com.myorg\nisRoot | boolean | no | This option defines where the certificate should be installed to: either Trusted Root Store (`true`, the default option) or the Keychain (`false`). On environments other than Xcode 11.4+ Simulator this option is ignored. | false\n\n### mobile: installCertificate > #### Returned Result\n\nThe content of the generated .mobileconfig file as base64-encoded string. This config might be useful for debugging purposes. If the certificate has been successfully set via CLI then nothing is returned.\n\n### mobile: removeCertificate\n\nRemoves installed certificate for real devices only if [py-ios-device](https://github.com/YueChen-C/py-ios-device) tool is available on the server machine since driver version 4.19.2.\n\n### mobile: removeCertificate > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nname | string | yes | Name of the profile | com.orgname.profile.mdmprofile\n\n### mobile: removeCertificate > #### Returned Result\n\nReturns status acknowledgment `{'Status': 'Acknowledged'}` if successfully removed certificate or `None` if unable to remove certificate.","metadata":{"headerPath":"### mobile: installCertificate","sectionCount":6,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: listCertificates\n\nLists installed certificates for real devices only if [py-ios-device](https://github.com/YueChen-C/py-ios-device) tool is available on the server machine since driver version 4.10.0.\n\n### mobile: listCertificates > #### Returned Result\n\nReturns map of certificates installed on the real device. The response looks like:\n\n```json\n{\n 'OrderedIdentifiers': ['com.orgname.profile.mdmprofile'],\n 'ProfileManifest': {\n 'com.orgname.profile.mdmprofile': {\n 'Description': 'MDM Profile',\n 'IsActive': True\n }\n },\n 'ProfileMetadata': {\n 'com.orgname.profile.mdmprofile': {\n 'PayloadDescription': 'MDM Profile for testing,\n 'PayloadDisplayName': 'MDM Profile',\n 'PayloadOrganization': 'My Org, Inc.',\n 'PayloadRemovalDisallowed': False,\n 'PayloadUUID': '9ab3fa27-cc45-4c23-a94a-714686397a86',\n 'PayloadVersion': 1\n }\n },\n 'Status': 'Acknowledged'\n}\n```\n\n### mobile: startLogsBroadcast\n\nStarts iOS system logs broadcast websocket on the same host and port where Appium server is running at `/ws/session/:sessionId:/appium/syslog` endpoint. The method will return immediately if the web socket is already listening.\nEach connected webcoket listener will receive syslog lines as soon as they are visible to Appium.\nRead [Using Mobile Execution Commands to Continuously Stream Device Logs with Appium](https://appiumpro.com/editions/55-using-mobile-execution-commands-to-continuously-stream-device-logs-with-appium) Appium Pro article for more details on this feature.\n\nConsider using [logs broadcast via BiDi](./bidi.md#logentryadded) over this extension.\n\n### mobile: stopLogsBroadcast\n\nStops the syslog broadcasting wesocket server previously started by `mobile: startLogsBroadcast`. This method will return immediately if no server is running.\n\nConsider using [logs broadcast via BiDi](./bidi.md#logentryadded) over this extension.\n\n### mobile: batteryInfo\n\nReads the battery information from the device under test. This endpoint only returns reliable result on real devices.","metadata":{"headerPath":"### mobile: listCertificates","sectionCount":5,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: batteryInfo > #### Returned Result\n\nThe returned object always includes at least the following entries:\n\n- `level`: Battery level in range [0.0, 1.0], where 1.0 means 100% charge.\n- `state`: Battery state as an integer number. The following values are possible:\n * UIDeviceBatteryStateUnknown = 0\n * UIDeviceBatteryStateUnplugged = 1 // on battery, discharging\n * UIDeviceBatteryStateCharging = 2 // plugged in, less than 100%\n * UIDeviceBatteryStateFull = 3 // plugged in, at 100%\n\nOn iOS 18 and newer real devices, the returned object may also include many additional advanced battery information fields, such as capacity, health metrics, temperature, and more. For a full list of possible advanced fields, see the [BatteryInfo](../../lib/commands/advanced-battery-types.ts).\n\nThe returned object is a superset of the basic battery info, and may look like:\n\n```json\n{\n \"level\": 0.85,\n \"state\": 2,\n \"advanced\": {\n \"AbsoluteCapacity\": 1234,\n \"CycleCount\": 456,\n \"Temperature\": 29.5,\n \"...\": \"other advanced fields\"\n }\n}\n```\n\nIf advanced fields are not available (e.g., on older iOS versions or simulators), only `level` and `state` will be present.\n\n### mobile: deviceInfo\n\nReturns the miscellaneous information about the device under test.\nIt includes device information via lockdown in a real device since XCUITest driver 4.2.0.","metadata":{"headerPath":"### mobile: batteryInfo > #### Returned Result","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: deviceInfo > #### Returned Result\n\nThe returned device information map contains the following entries:\n\nName | Type | Description | Example\n--- | --- | --- | ---\ncurrentLocale | string | Device locale name. See [autoupdatingCurrentLocale](https://developer.apple.com/documentation/foundation/nslocale/1414388-autoupdatingcurrentlocale) for more details. | ja_EN, zh-Hant_US\ntimeZone | string | Device time zone name. See [NSTimeZone](https://developer.apple.com/documentation/foundation/nstimezone?language=objc) documentation for more details. | America/New_York\nname | string | Device name, synonym for model. Prior to iOS 16, user-assigned device name. See [UIDevice.name](https://developer.apple.com/documentation/uikit/uidevice/1620015-name?language=objc) documentation for more details. | iPhone\nmodel | string | The model of the device. See [UIDevice.model](https://developer.apple.com/documentation/uikit/uidevice/1620044-model?language=objc) documentation for more details. | iPod touch\nuuid | string | Device [identifier for vendor](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor?language=objc). Could be equal to `unknown` if cannot be retrieved. | 12345abcd\nuserInterfaceIdiom | number | The style of the interface on the current device. Could help to determine the device type (e.g. iPhone vs iPad). See [UIDevice.userInterfaceIdiom](https://developer.apple.com/documentation/uikit/uidevice/1620037-userinterfaceidiom?language=objc) for more details. | 0 (UIUserInterfaceIdiomUnspecified), 1 (UIUserInterfaceIdiomPhone), 2 (UIUserInterfaceIdiomPad), 3 (UIUserInterfaceIdiomTV)\nuserInterfaceStyle | string | The device's UI [appearance](https://developer.apple.com/documentation/xctest/xcuidevice/4108227-appearance?language=objc) style. Possible values are: `automatic`, `light`, `dark`, `unknown`. | dark\nisSimulator | number | Whether the device is a simulator (1) or a real device (0) | 1\nthermalState | number | Thermal state of the device. See [NSProcessInfoThermalState](https://developer.apple.com/documentation/foundation/nsprocessinfothermalstate) documentation on possible values. | 0 (NSProcessInfoThermalStateNominal), 1 (NSProcessInfoThermalStateFair), 2 (NSProcessInfoThermalStateSerious), 3 (NSProcessInfoThermalStateCritical)\n\n### mobile: getDeviceTime\n\nReturns the actual device time.","metadata":{"headerPath":"### mobile: deviceInfo > #### Returned Result","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: getDeviceTime > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nformat | string | no | The format specifier string. Read [MomentJS documentation](https://momentjs.com/docs/) to get the full list of supported datetime format specifiers. The default format is `YYYY-MM-DDTHH:mm:ssZ`, which complies to ISO-8601 | `YYYY-MM-DD HH:mm:ss`\n\n### mobile: getDeviceTime > #### Returned Result\n\nThe retrieved datetime string formatted according to the given format specfier.\n\n### mobile: activeAppInfo\n\nReturns information about the active application.\n\n### mobile: activeAppInfo > #### Returned Result\n\nThe API returns a map with the following entries\n\nName | Type | Description | Example\n--- | --- | --- | ---\npid | number | The process identifier of the active application | 1234\nbundleId | string | The bundle identifier of the active application | com.yolo.myapp\nname | string | The name of the active application, if present | Safari\nprocessArguments | map | The map containing actual process arguments. Check the description of the [appium:processArguments capability](./capabilities.md#webdriveragent) for more details on its format. Might be empty if no process arguments have been provided on the app startup. | {\"args\": [\"--help\"], \"env\": {\"PATH\": \"/\"}}\n\n### mobile: pressButton\n\nEmulates press action on the given physical device button. iOS is [pressButton:](https://developer.apple.com/documentation/xctest/xcuidevice/1619052-pressbutton), tvOS is [pressButton:](https://developer.apple.com/documentation/xctest/xcuiremote/1627475-pressbutton) or [pressButton:forDuration:](https://developer.apple.com/documentation/xctest/xcuiremote/1627476-pressbutton).\n[mobile: performIoHidEvent](#mobile-performiohidevent) calls a more universal API to perform press with duration on any supported device.\n\n### mobile: pressButton > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nname | string | yes | The name of the button to be pressed. Supported button names for iOS-based devices are (case-insensitive): `home`, `volumeup`, `volumedown`. For tvOS-based devices (case-insensitive): `home`, `up`, `down`, `left`, `right`, `menu`, `playpause`, `select` | home\ndurationSeconds | number | no | Duration in float seconds for tvOS-based devices since Appium 1.22.0 | 10","metadata":{"headerPath":"### mobile: getDeviceTime > #### Arguments","sectionCount":6,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: pushNotification\n\nSimulates push notification delivery to Simulator.\nOnly application remote push notifications are supported. VoIP, Complication, File Provider,\nand other types are not supported. Check the output of `xcrun simctl help push`\ncommand for more details.\n\n### mobile: pushNotification > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the target application | com.apple.Preferences\npayload | map | yes | Valid Apple Push Notification values. Read the `Create the JSON Payload` topic of the [official Apple documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification?language=objc) for more details on the payload creation. | `{\"aps\": {\"alert\": {\"title\": \"This is a simulated notification!\"}, \"badge\": 3, \"sound\": \"default\"} }`\n\n### mobile: expectNotification\n\nBlocks until the expected notification is delivered.\nIt is a thin wrapper over [XCTNSNotificationExpectation](https://developer.apple.com/documentation/xctest/xctnsnotificationexpectation?language=objc) and\n[XCTDarwinNotificationExpectation](https://developer.apple.com/documentation/xctest/xctdarwinnotificationexpectation?language=objc) entities.\nThe extension call throws [TimeoutError](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/lib/error_exports_TimeoutError.html) if the expected notification has not been delivered within the given timeout.\n\n### mobile: expectNotification > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nname | string | yes | The name of the notification to expect | com.example.fooAllDone\ntype | string | no | Which notification type to expect. Either `plain` (the default value) to wait for a notification from the *default* notification center or `darwin` to wait for a system notification. | darwin\ntimeoutSeconds | number | no | For how long to wait until the notification is delivered in float seconds. 60 seconds by default | 5.5","metadata":{"headerPath":"### mobile: pushNotification","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: performIoHidEvent\n\nEmulates triggering of the given low-level IO HID device event. Constants for possible events are defined\nin [HID Usage Tables](https://developer.apple.com/documentation/hiddriverkit/hid_usage_tables).\nFor example, in order to emulate single press on Home button the extension should be called with the following arguments:\n- page: `0x0C` (`kHIDPage_Consumer`, select the `Customer` page)\n- usage: `0x40` (`kHIDUsage_Csmr_Menu`, the `Csmr` prefix here means this usage is dedicated to the `Customer` page)\n- durationSeconds: `0.005` (The event duration should be 5 milliseconds to be recognized as a single press by iOS)\n\nSome popular constants:\n\nName | Value | Description\n--- | --- | ---\nkHIDPage_Consumer | 0x0C | The page containing all usages prefixed with `kHIDUsage_Csmr_`\nkHIDUsage_Csmr_VolumeIncrement | 0xE9 | Volume Up\nkHIDUsage_Csmr_VolumeDecrement | 0xEA | Volume Down\nkHIDUsage_Csmr_Menu | 0x40 | Home\nkHIDUsage_Csmr_Power | 0x30 | Power/Lock\nkHIDUsage_Csmr_Snapshot | 0x65 | Power + Home\n\n### mobile: performIoHidEvent > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\npage | int | yes | The event page identifier. Look for constants perfixed with `kHIDPage_` in the table above | 0x0C\nusage | int | yes | The event usage identifier (usages are defined per-page). Look for constants prefixed with `kHIDUsage_` in the table above | 0x40\ndurationSeconds | number | yes | The event duration in float seconds. XCTest uses `0.005` for a single press event duration | 2.5\n\n### mobile: enrollBiometric\n\nEnrolls biometric authentication on Simulator.\n\n### mobile: enrollBiometric > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nisEnabled | boolean | no | Whether to enable/disable biometric enrollment. `true` by default. | true\n\n### mobile: sendBiometricMatch\n\nEmulates biometric match/non-match event on Simulator. The biometric feature is expected to be already enrolled before executing that.\n\n### mobile: sendBiometricMatch > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntype | string | no | The biometric feature name. Either `touchId` or `faceId`. `touchId` by default. | faceId\nmatch | boolean | no | Whether to simulate biometric match (`true`, the default value) or non-match (`false`). | true\n\n### mobile: isBiometricEnrolled\n\nChecks whether biometric is currently enrolled or not on a Simulator device.","metadata":{"headerPath":"### mobile: performIoHidEvent","sectionCount":7,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: isBiometricEnrolled > #### Returned Result\n\nEither `true` or `false`\n\n### mobile: clearKeychains\n\nClears keychains on Simulator. An exception is thrown for real devices.\n\n### mobile: getPermission\n\nGets application permission state on Simulator. This method requires [WIX applesimutils](https://github.com/wix/AppleSimulatorUtils) to be installed on the host where Appium server is running.\n\n### mobile: getPermission > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the destination app. | com.mycompany.myapp\nservice | string | yes | One of available service names. The following services are supported: `calendar`, `camera`, `contacts`, `homekit`, `microphone`, `photos`, `reminders`, `medialibrary`, `motion`, `health`, `siri`, `speech`. | true\n\n### mobile: getPermission > #### Returned Result\n\nEither 'yes', 'no', 'unset' or 'limited'\n\n### mobile: setPermission\n\nSet application permission state on Simulator.\n\n`location` and `location-always` services are by `xcrun simctl privacy` command since XCUITest driver version 5.11.0.\nThe command will kill the `bundleId` application process if it is running.\n\nOther services such as `contacts` are processed by [WIX applesimutils](https://github.com/wix/AppleSimulatorUtils), which will not kill the `bundleId` application process.\n[WIX applesimutils](https://github.com/wix/AppleSimulatorUtils) needs to be installed on the host where Appium server is running.","metadata":{"headerPath":"### mobile: isBiometricEnrolled > #### Returned Result","sectionCount":6,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: setPermission > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundleId | string | yes | The bundle identifier of the destination app. | com.mycompany.myapp\naccess | map | yes | One or more access rules to set. The following keys are supported: `all` (Apply the action to all services), `calendar` (Allow access to calendar), `contacts-limited` (Allow access to basic contact info), `contacts` (Allow access to full contact details), `location` (Allow access to location services when app is in use), `location-always` (Allow access to location services at all times), `photos-add` (Allow adding photos to the photo library), `photos` (Allow full access to the photo library), `media-library` (Allow access to the media library), `microphone` (Allow access to audio input), `motion` (Allow access to motion and fitness data), `reminders` (Allow access to reminders), `siri` (Allow use of the app with Siri.). The following values are supported: `yes` (To grant the permission), `no` (To revoke the permission), `unset` (To reset the permission) | {'all': 'yes'}\n\n### mobile: resetPermission\n\nResets the given permission for the active application under test. Works for both Simulator and real devices using Xcode SDK 11.4+\n\n### mobile: resetPermission > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nservice | string or int | yes | One of available service names. The supported service names are: `calendar`, `camera`, `contacts`, `health`, `homekit`, `keyboardnet`, `location`, `medialibrary`, `microphone`, `photos`, `reminders`, `systemroot`, `userdesktop`, `userdocuments`, `userdownloads`, `bluetooth`. This could also be an integer protected resource identifier taken from [XCUIProtectedResource](https://developer.apple.com/documentation/xctest/xcuiprotectedresource?language=objc) | photos\n\n### mobile: getAppearance\n\nGet the device's UI appearance style.\n\n### mobile: getAppearance > #### Returned Result\n\nAn object, with the following entries:\n- style: The device's UI appearance value. This could be one of: `light`, `dark`, `unknown`, `unsupported`\n\n### mobile: setAppearance\n\nSet the device's UI appearance style.\n\n### mobile: setAppearance > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nstyle | string | yes | Either `light` or `dark` | dark","metadata":{"headerPath":"### mobile: setPermission > #### Arguments","sectionCount":7,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: getIncreaseContrast\n\nGet the device's \"increase contrast\" accessibility mode.\nThis API only works on simulators. An exception is thrown if executed with real devices.\n\n### mobile: getIncreaseContrast > #### Returned Result\n\nOne of below:\n\n- `enabled`: Increase Contrast is enabled.\n- `disabled`: Increase Contrast is disabled.\n- `unsupported`: The platform or runtime version does not support the Increase Contrast setting.\n- `unknown`: The current setting is unknown or there was an error detecting it.\n\n### mobile: setIncreaseContrast\n\nEnable or disable the device's \"increase contrast\" accessibility mode.\nThis API only works on simulators. An exception is thrown if executed with real devices.\n\n### mobile: setIncreaseContrast > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nincreaseContrast | string | yes | Either `enabled` or `disabled` (case insensitive) | 'enabled'\n\n### mobile: contentSize\n\nGet the device's content size.\nThis API only works on simulators. An exception is thrown if executed with real devices.\n\n### mobile: contentSize > #### Returned Result\n\nOne of below:\n\n- `extra-small`\n- `small`\n- `medium`\n- `large`\n- `extra-large`\n- `extra-extra-large`\n- `extra-extra-extra-large`\n- `accessibility-medium`\n- `accessibility-large`\n- `accessibility-extra-large`\n- `accessibility-extra-extra-large`\n- `accessibility-extra-extra-extra-large`\n- `unknown`\n- `unsupported`\n\n### mobile: setContentSize\n\nSet the device's content size.\nThis API only works on simulators. An exception is thrown if executed with real devices.\n\n### mobile: setContentSize > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nsize | string | yes | One of the content sizes listed below in case-insensitive. | large\n\n- `extra-small`\n- `small`\n- `medium`\n- `large`\n- `extra-large`\n- `extra-extra-large`\n- `extra-extra-extra-large`\n- `accessibility-medium`\n- `accessibility-large`\n- `accessibility-extra-large`\n- `accessibility-extra-extra-large`\n- `accessibility-extra-extra-extra-large`\n\n### mobile: getClipboard\n\nGets the content of the primary clipboard on the device under test.\n\n### mobile: getClipboard > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncontentType | string | no | `plaintext` (default), `image` or `url` | image","metadata":{"headerPath":"### mobile: getIncreaseContrast","sectionCount":10,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: getClipboard > #### Returned Result\n\nThe actual clipboard content encoded into base64 string.\nAn empty string is returned if the clipboard contains no data.\n\n### mobile: setClipboard\n\nSets the primary clipboard's content on the device under test.\n\n### mobile: setClipboard > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncontent| string | yes | The content to be set as base64-encoded string. | QXBwaXVt\ncontentType | string | no | `plaintext` (default), `image` or `url` | image\n\n### mobile: siriCommand\n\nPresents the Siri UI, if it is not currently active, and accepts a string which is then processed as if it were recognized speech. Check the documentation on [activateWithVoiceRecognitionText](https://developer.apple.com/documentation/xctest/xcuisiriservice/2852140-activatewithvoicerecognitiontext?language=objc) XCTest method for more details.\n\n### mobile: siriCommand > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntext | string | yes | The actual command that will be passed to Siri service | Hello Siri\n\n### mobile: pullFile\n\nPulls a remote file from the device.\n\n### mobile: pullFile > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | The path to an existing remote file on the device. See the [File Transfer](../guides/file-transfer.md) guide for accepted formats. If the file with the given name does not exist an exception will be thrown. | @com.mycompany.myapp:documents/myfile.txt\n\n### mobile: pullFile > #### Returned Result\n\nBase64-encoded string, which represents the content of the remote file.\n\n### mobile: pushFile\n\nPushes a local file to the device.\n\n### mobile: pushFile > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | The path on the device to where the payload should be written. The value format is similar to the one used in [pullFile](#mobile-pullfile) extension. If the file with the same name already exists then it will be silently overridden. | @com.mycompany.myapp:documents/myfile.txt\npayload | string | yes | Base64-encoded content of the file to be pushed. | QXBwaXVt\n\n### mobile: pullFolder\n\nPulls a remote folder from the device.","metadata":{"headerPath":"### mobile: getClipboard > #### Returned Result","sectionCount":11,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: pullFolder > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | Same as for [pullFile](#mobile-pullfile) extension, but should be pointing to a remote folder | @com.mycompany.myapp:documents/myfolder/\n\n### mobile: pullFolder > #### Returned Result\n\nBase64-encoded string, which represents the zipped content of the remote folder.\n\n### mobile: deleteFile\n\nDeletes the given file from the device under test.\n\n### mobile: deleteFile > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | Same as for [pullFile](#mobile-pullfile) extension | @com.mycompany.myapp:documents/myfile.txt\n\n### mobile: deleteFolder\n\nDeletes the given folder from the device under test.\n\n### mobile: deleteFolder > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | yes | Same value as for `mobile: deleteFile` except of the fact it should be pointing to a folder and should end with a single slash `/` | @com.mycompany.myapp:documents/myfolder/\n\n### mobile: configureLocalization\n\nChange localization settings on the currently booted Simulator.\nThe changed settings are only applied for the *newly started* applications/activities.\nCurrently running applications will stay unchanged. This means, for example, that the keyboard\nshould be hidden and shown again in order to observe the changed layout, and corresponding\napps must be restarted in order to observe their interface using the newly set locale/language.\nAlso this method might leave some system UI alerts untranslated.\nBe careful while setting the actual arguments since their actual values are not strictly checked.\nThis could lead to an unexpected behavior if an incorrect/unsupported language or locale abbreviation is provided.","metadata":{"headerPath":"### mobile: pullFolder > #### Arguments","sectionCount":7,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: configureLocalization > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nkeyboard | map | no | On-screen keyboard properties. The `name` key is required and should be set to a valid locale abbreviation. The `layout` key is also required. The `hardware` key is optional and could be omitted or set to `Automated`. You could switch the keyboard layout in system preferences of your booted simulator, run `xcrun simctl spawn booted defaults read .GlobalPreferences.plist`, and inspect the value of `AppleKeyboards` to see possible combinations. | `{\"name\": \"de_CH\", \"layout\": \"QWERTZ\", \"hardware\": \"Automated\"}`\nlanguage | map | no | System language properties. The `name` key is required and should be set to a valid language abbreviation. You could switch the system language in preferences of your booted simulator, run `xcrun simctl spawn booted defaults read .GlobalPreferences.plist`, and inspect the value of `AppleLanguages` to see possible combinations. | `{\"name\": \"zh-Hant-CN\"}`\nlocale | map | no | System locale properties. The `name` key is required and should be set to a valid language abbreviation. The `calendar`key is optional and could be set to a valid calendar format name. You could switch the system locale/calendar format in preferences of your booted simulator, run `xcrun simctl spawn booted defaults read .GlobalPreferences.plist`, and inspect the value of `AppleLocale` to see possible combinations. | `{\"name\": \"uk_UA\", \"calendar\": \"gregorian\"}`\n\n### mobile: configureLocalization > #### Returned Result\n\n`true` if any of settings has been successfully changed.\n\n### mobile: startAudioRecording\n\nRecords the given hardware audio input into an .mp4 file. You must allow the `audio_record` security feature in order to use this extension. Also it is required that [FFMpeg](https://ffmpeg.org/) is installed on the machibe where Appium server is running.","metadata":{"headerPath":"### mobile: configureLocalization > #### Arguments","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: startAudioRecording > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\naudioInput | string or int | yes | The name of the corresponding audio input device to use for the capture. The full list of capture devices could be shown using `ffmpeg -f avfoundation -list_devices true -i \"\"` Terminal command. | 1\naudioCodec | string | no | The name of the audio codec. The Advanced Audio Codec (aac) is used by default. | aac\naudioBitrate | string | no | The bitrate of the resulting audio stream. `128k` by default. | 256k\naudioChannels | string or int | no | The count of audio channels in the resulting stream. Setting it to `1` will create a single channel (mono) audio stream. `2` By default | 1\naudioRate | string or int | no | The sampling rate of the resulting audio stream. 44100 by default | 22050\ntimeLimit | string or int | no | The maximum recording time, in seconds. The default value is `180`, the maximum value is `43200` (12 hours). | 60\nforceRestart | boolean | no | Whether to restart audio capture process forcefully when startRecordingAudio is called (`true`) or ignore the call until the current audio recording is completed (`false`, the default value). | true\n\n### mobile: stopAudioRecording\n\nStops recording of the audio input. If no audio recording process is running then the endpoint will try to get the recently recorded file. If no previously recorded file is found and no active audio recording processes are running then the method returns an empty string.\n\n### mobile: stopAudioRecording > #### Returned Result\n\nBase64-encoded content of the recorded media file or an empty string if no audio recording has been started before.\n\n### mobile: startPcap\n\nStart mobile device network traffic capture. This extension only works if [py-ios-device](https://github.com/YueChen-C/py-ios-device) utility is installed on the server machine and only supports\nreal iOS devices.\n\n### mobile: startPcap > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntimeLimitSec | string or int | no | The maximum recording time, in seconds. The default value is `180`, the maximum value is `43200` (12 hours). | 60\nforceRestart | boolean | no | Whether to restart traffic capture process forcefully when startPcap is called (`true`) or ignore the call until the current traffic capture is completed (`false`, the default value). | true","metadata":{"headerPath":"### mobile: startAudioRecording > #### Arguments","sectionCount":5,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: stopPcap\n\nStops network traffic capture. If no traffic capture process is running then the endpoint will try to get the recently recorded file. If no previously recorded file is found and no active traffic capture processes are running then the method returns an empty string.\n\n### mobile: stopPcap > #### Returned Result\n\nBase64-encoded content of the traffic capture file (.pcap) or an empty string if no traffic capture has been started before. Network capture files could be opened in [Wireshark](https://www.wireshark.org/) application.\n\n### mobile: runXCTest\n\nRun a native XCTest script. Launches a subprocess that runs the XC Test and blocks until it is completed. Parses the stdout of the process and returns its result as an array. Facebook's [IDB](https://github.com/facebook/idb) tool is required to run such tests.\n\n### mobile: runXCTest > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ntestRunnerBundleId | string | yes | Test app bundle | io.appium.XCTesterAppUITests.xctrunner\nappUnderTestBundleId | string | yes | App-under-test bundle | com.mycompany.myapp\nxcTestBundleID | string | yes | xctest bundle id | io.appium.XCTesterAppUITests\ntestType | string | no | Test type. Either `ui` (the default one), `app` or `logic` | app\nenv | map | no | Environment variables mapping to be passed to the test | {'myvar': 'myvalue'}\nargs | array | no | Launch arguments to start the test with (see https://developer.apple.com/documentation/xctest/xcuiapplication/1500477-launcharguments for reference) | ['-arg1', '--arg2']\ntimeout | string or int | no | Timeout if session doesn't complete after given time (in milliseconds). `360000`ms by default | 120000\n\n### mobile: runXCTest > #### Returned Result\n\nThe API calls returns a map with the following entries:\n\n- results: The array of test results. Each item in this array conists of the following entries:\n * testName: Name of the test (e.g.: 'XCTesterAppUITests - XCTesterAppUITests.XCTesterAppUITests/testExample')\n * passed: Did the tests pass?\n * crashed: Did the tests crash?\n * status: Test result status (e.g.: 'passed', 'failed', 'crashed')\n * duration: How long did the tests take (in seconds)\n * failureMessage: Failure message (if applicable)\n * location The geolocation of the test (if applicable)\n- code: The exit code of the process. `0` value marks a successful execution.\n- signal: The signal that terminated the process. Could be `null` (e.g.: `SIGTERM`)","metadata":{"headerPath":"### mobile: stopPcap","sectionCount":5,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: installXCTestBundle\n\nInstalls an XCTest bundle to the device under test. Facebook's [IDB](https://github.com/facebook/idb) tool is required to for this API to work.\n\n### mobile: installXCTestBundle > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nxctestBundle | string | yes | Path to your xctest .app bundle. Could be an URL | /path/to/my/bundle.app\n\n### mobile: listXCTestBundles\n\nList XCTest bundles that are installed on device. Facebook's [IDB](https://github.com/facebook/idb) tool is required to for this API to work.\n\n### mobile: listXCTestBundles > #### Returned Result\n\nArray of XCTest bundles (e.g.: [\"XCTesterAppUITests.XCTesterAppUITests/testLaunchPerformance\"])\n\n### mobile: listXCTestsInTestBundle\n\nList XCTests in a test bundle. Facebook's [IDB](https://github.com/facebook/idb) tool is required to for this API to work.\n\n### mobile: listXCTestsInTestBundle > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nbundle | string | yes | Bundle ID of the XCTest | 'com.bundle.myapp'\n\n### mobile: listXCTestsInTestBundle > #### Returned Result\n\nArray of xctests in the test bundle (e.g.: `[ 'XCTesterAppUITests.XCTesterAppUITests/testExample', 'XCTesterAppUITests.XCTesterAppUITests/testLaunchPerformance' ]`)\n\n### mobile: viewportRect\n\nRetrieves the viewport dimensions.\nThe viewport is the device's screen size with status bar size subtracted if the latter is present/visible.\n\n### mobile: viewportRect > #### Returned Result\n\nThe response looks like `{\"value\":{\"left\":0,\"top\":96,\"width\":828,\"height\":1696}}`.\n\n`left` and `top` are distance from the `left` of the screen and the `top` of the screen. [iOS Drawing Concepts](https://developer.apple.com/library/archive/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html) could help about the relationship of coordinate.\n\n`width` and `height` are the screen's width and height.\n\n### mobile: viewportScreenshot\n\nTakes a screenshot of the device viewport (see [`mobile: viewportRect`](#mobile-viewportrect))\n\n!!! warning \"Unreliable\"\n\n This method is unreliable. We recommend using `getScreenshot` instead\n\n### mobile: viewportScreenshot > #### Returned Result\n\nBase64-encoded string, which represents the viewport screenshot.\n\n### mobile: deviceScreenInfo\n\nGet information about screen.","metadata":{"headerPath":"### mobile: installXCTestBundle","sectionCount":12,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: deviceScreenInfo > #### Returned Result\n\nThe response looks like `{\"value\":{\"statusBarSize\":{\"width\":414,\"height\":48},\"scale\":2}}`\n\n`statusBarSize` contains status bar dimensions. It is the result of [status bar](https://developer.apple.com/documentation/xctest/xcuielementtypequeryprovider/1500428-statusbars).\n`scale` is [screen scale](https://developer.apple.com/documentation/uikit/uiscreen/1617836-scale).\n\n### mobile: swipe\n\nThis gesture performs a simple \"swipe\" gesture on the particular screen element or\non the application element, which is usually the whole screen. This method does not\naccept coordinates and simply emulates single swipe with one finger. It might be\nuseful for such cases like album pagination, switching views, etc. More advanced\ncases may require to call [mobile: dragFromToForDuration](#mobile-dragfromtoforduration),\nwhere one can supply coordinates and duration.\n\n### mobile: swipe > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to swipe on. Application element will be used instead if this argument is not provided | fe50b60b-916d-420b-8728-ee2072ec53eb\ndirection | Either 'up', 'down', 'left' or 'right' | yes | The direction in which to swipe | up\nvelocity | number | no | This argument is optional and is only supported since Appium server version 1.19 and Xcode SDK version 11.4+. The value is measured in pixels per second and same values could behave differently on different devices depending on their display density. Higher values make swipe gesture faster (which usually scrolls larger areas if we apply it to a list) and lower values slow it down. Only values greater than zero have effect. | 250","metadata":{"headerPath":"### mobile: deviceScreenInfo > #### Returned Result","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: swipe > #### Examples\n\n=== \"Java\"\n\n ```java\n RemoteWebElement e = driver.findElement(AppiumBy.accessibilityId(\"target element\"));\n driver.executeScript(\"mobile: swipe\", ImmutableMap.of(\n \"velocity\": 2500,\n \"direction\": \"down\",\n \"elementId\", e.getId()\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const e = await $('~target element');\n await driver.executeScript(\"mobile: swipe\", [{\n velocity: 2500,\n direction: \"down\",\n elementId: e.elementId\n }]);\n\n=== \"Python\"\n\n ```python\n e = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='target element')\n driver.execute_script(\"mobile: swipe\", {\n \"velocity\": 2500,\n \"direction\": \"down\",\n \"elementId\": e.id\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n e = driver.find_element :accessibility_id, 'target element'\n driver.execute_script 'mobile: swipe', {\n velocity: 2500,\n direction: 'down',\n elementId: e.ref\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n var e = driver.FindElement(By.AccessibilityId(\"target element\"))\n driver.ExecuteScript(\"mobile: swipe\", new Dictionary<string, object>() {\n {\"elementId\", element.Id},\n {\"direction\", \"down\" },\n {\"velocity\", 2500 }\n });\n ```\n\n### mobile: swipe > #### References\n\n- [swipeDown](https://developer.apple.com/documentation/xctest/xcuielement/1618664-swipedown?language=objc)\n- [swipeDownWithVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/3551694-swipedownwithvelocity?language=objc)\n- [swipeUp](https://developer.apple.com/documentation/xctest/xcuielement/1618667-swipeup?language=objc)\n- [swipeUpWithVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/3551697-swipeupwithvelocity?language=objc)\n- [swipeLeft](https://developer.apple.com/documentation/xctest/xcuielement/1618668-swipeleft?language=objc)\n- [swipeLeftWithVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/3551695-swipeleftwithvelocity?language=objc)\n- [swipeRight](https://developer.apple.com/documentation/xctest/xcuielement/1618674-swiperight?language=objc)\n- [swipeRightWithVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/3551696-swiperightwithvelocity?language=objc)","metadata":{"headerPath":"### mobile: swipe > #### Examples","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: scroll\n\nScrolls the element or the whole screen. Different scrolling strategies are supported.\nArguments define the chosen strategy: either 'name', 'direction', 'predicateString' or\n'toVisible' in that order. All strategies are exclusive and only one strategy\ncan be applied at a single moment of time. Use \"mobile: scroll\" to emulate precise\nscrolling in tables or collection views, where it is already known to which element\nthe scrolling should be performed. Although, there is one known limitation there: in case\nit is necessary to perform too many scroll gestures on parent container to reach the\nnecessary child element (tens of them) then the method call may fail.\n_Important_: The implementation of this extension relies on several undocumented XCTest features, which might not always be reliable. Thus it might *not* always work as expected.\n\n### mobile: scroll > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to scroll on (e.g. the container). The active application element will be used instead if this parameter is not provided. | fe50b60b-916d-420b-8728-ee2072ec53eb\nname | string | no | The accessibility id of the child element, to which scrolling is performed. The same result can be achieved by setting _predicateString_ argument to 'name == accessibilityId'. Has no effect if _elementId_ is not a container | cell12\ndirection | Either 'up', 'down', 'left' or 'right' | yes | The main difference from [swipe](#mobile-swipe) call with the same argument is that _scroll_ will try to move the current viewport exactly to the next/previous page (the term \"page\" means the content, which fits into a single device screen) | down\npredicateString | string | no | The NSPredicate locator of the child element, to which the scrolling should be performed. Has no effect if _elementId_ is not a container | label == \"foo\"\ntoVisible | boolean | no | If set to _true_ then asks to scroll to the first visible _elementId_ in the parent container. Has no effect if _elementId_ is not set | true","metadata":{"headerPath":"### mobile: scroll","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: scroll > #### Examples\n\n=== \"Java\"\n\n ```java\n driver.executeScript(\"mobile: scroll\", ImmutableMap.of(\n \"direction\", \"down\"\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n await driver.executeScript('mobile: scroll', [{\n direction: 'down'\n }]);\n\n=== \"Python\"\n\n ```python\n driver.execute_script(\"mobile: scroll\", {\n \"direction\": \"down\"\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n driver.execute_script 'mobile: scroll', {\n direction: 'down'\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n driver.ExecuteScript(\"mobile: scroll\", new Dictionary<string, object>() {\n {\"direction\", \"down\"}\n });\n ```\n\n### mobile: pinch\n\nPerforms pinch gesture on the given element or on the application element.\n\n### mobile: pinch > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to pinch on. The active application element will be used instead if this parameter is not provided. | fe50b60b-916d-420b-8728-ee2072ec53eb\nscale | number | yes | Pinch scale of type float. Use a scale between 0 and 1 to \"pinch close\" or zoom out and a scale greater than 1 to \"pinch open\" or zoom in. | 0.5\nvelocity | number | yes | The velocity of the pinch in scale factor per second (float value) | 2.2","metadata":{"headerPath":"### mobile: scroll > #### Examples","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: pinch > #### Examples\n\n=== \"Java\"\n\n ```java\n RemoteWebElement e = driver.findElement(AppiumBy.accessibilityId(\"target element\"));\n driver.executeScript(\"mobile: pinch\", ImmutableMap.of(\n \"scale\", 0.5,\n \"velocity\", 1.1,\n \"elementId\", e.getId()\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const e = await $('~target element');\n await driver.executeScript('mobile: pinch', [{\n scale: 0.5,\n velocity: 1.1,\n elementId: e.elementId\n }]);\n\n=== \"Python\"\n\n ```python\n e = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='target element')\n driver.execute_script(\"mobile: pinch\", {\n \"scale\": 0.5,\n \"velocity\": 1.1,\n \"elementId\": e.id\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n e = driver.find_element :accessibility_id, 'target element'\n driver.execute_script 'mobile: pinch', {\n scale: 0.5,\n velocity: 1.1,\n elementId: e.ref\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n var e = driver.FindElement(By.AccessibilityId(\"target element\"))\n driver.ExecuteScript(\"mobile: pinch\", new Dictionary<string, object>() {\n {\"elementId\", element.Id},\n {\"scale\", 0.5 },\n {\"velocity\", 1.1 },\n });\n ```\n\n### mobile: pinch > #### Reference\n\n[pinchWithScale:velocity:](https://developer.apple.com/documentation/xctest/xcuielement/1618669-pinchwithscale?language=objc)\n\n### mobile: doubleTap\n\nPerforms double tap gesture on the given element or on the screen.\n\n### mobile: doubleTap > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to double tap on. The active application element will be used instead if this parameter is not provided. | fe50b60b-916d-420b-8728-ee2072ec53eb\nx | number | no | Horizontal coordinate offset. | 100\ny | number | no | Vertical coordinate offset. | 100","metadata":{"headerPath":"### mobile: pinch > #### Examples","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: doubleTap > #### Examples\n\n=== \"Java\"\n\n ```java\n RemoteWebElement e = driver.findElement(AppiumBy.accessibilityId(\"target element\"));\n driver.executeScript(\"mobile: doubleTap\", ImmutableMap.of(\n \"elementId\", e.getId()\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const e = await $('~target element');\n await driver.executeScript('mobile: doubleTap', [{\n elementId: e.elementId\n }]);\n\n=== \"Python\"\n\n ```python\n e = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='target element')\n driver.execute_script(\"mobile: doubleTap\", {\n \"elementId\": e.id\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n e = driver.find_element :accessibility_id, 'target element'\n driver.execute_script 'mobile: doubleTap', {\n elementId: e.ref\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n var e = driver.FindElement(By.AccessibilityId(\"target element\"))\n driver.ExecuteScript(\"mobile: doubleTap\", new Dictionary<string, object>() {\n {\"elementId\", element.Id}\n });\n ```\n\n### mobile: touchAndHold\n\nPerforms long press gesture on the given element or on the screen.\n\n### mobile: touchAndHold > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to long tap on. The active application element will be used instead if this parameter is not provided. | fe50b60b-916d-420b-8728-ee2072ec53eb\nduration | number | yes | The float duration of press action in seconds | 1.5\nx | number | no | Horizontal coordinate offset. | 100\ny | number | no | Vertical coordinate offset. | 100","metadata":{"headerPath":"### mobile: doubleTap > #### Examples","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: touchAndHold > #### Examples\n\n=== \"Java\"\n\n ```java\n RemoteWebElement e = driver.findElement(AppiumBy.accessibilityId(\"target element\"));\n driver.executeScript(\"mobile: touchAndHold\", ImmutableMap.of(\n \"elementId\", e.getId(),\n \"duration\", 2.0\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const e = await $('~target element');\n await driver.executeScript('mobile: touchAndHold', [{\n elementId: e.elementId,\n duration: 2.0\n }]);\n\n=== \"Python\"\n\n ```python\n e = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='target element')\n driver.execute_script(\"mobile: touchAndHold\", {\n \"elementId\": e.id,\n \"duration\": 2.0\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n e = driver.find_element :accessibility_id, 'target element'\n driver.execute_script 'mobile: touchAndHold', {\n elementId: e.ref,\n duration: 2.0\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n var e = driver.FindElement(By.AccessibilityId(\"target element\"))\n driver.ExecuteScript(\"mobile: touchAndHold\", new Dictionary<string, object>() {\n {\"elementId\", element.Id},\n {\"duration\", 2.0}\n });\n ```\n\n### mobile: touchAndHold > #### Reference\n\n[pressForDuration:](https://developer.apple.com/documentation/xctest/xcuielement/1618663-pressforduration?language=objc)\n\n### mobile: twoFingerTap\n\nPerforms two finger tap gesture on the given element or on the application element.\n\n### mobile: twoFingerTap > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to tap on. The active application element will be used instead if this parameter is not provided. | fe50b60b-916d-420b-8728-ee2072ec53eb","metadata":{"headerPath":"### mobile: touchAndHold > #### Examples","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: twoFingerTap > #### Examples\n\n=== \"Java\"\n\n ```java\n RemoteWebElement e = driver.findElement(AppiumBy.accessibilityId(\"target element\"));\n driver.executeScript(\"mobile: twoFingerTap\", ImmutableMap.of(\n \"elementId\", e.getId()\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const e = await $('~target element');\n await driver.executeScript('mobile: twoFingerTap', [{\n elementId: e.elementId\n }]);\n\n=== \"Python\"\n\n ```python\n e = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='target element')\n driver.execute_script(\"mobile: twoFingerTap\", {\n \"elementId\": e.id\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n e = driver.find_element :accessibility_id, 'target element'\n driver.execute_script 'mobile: twoFingerTap', {\n elementId: e.ref\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n var e = driver.FindElement(By.AccessibilityId(\"target element\"))\n driver.ExecuteScript(\"mobile: twoFingerTap\", new Dictionary<string, object>() {\n {\"elementId\", element.Id}\n });\n ```\n\n### mobile: twoFingerTap > #### Reference\n\n[twoFingerTap](https://developer.apple.com/documentation/xctest/xcuielement/1618675-twofingertap?language=objc)\n\n### mobile: tap\n\nPerforms tap gesture by coordinates on the given element or on the screen.\n\n### mobile: tap > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to tap on. _x_ and _y_ tap coordinates will be calculated relatively to the current element position on the screen if this argument is provided. Otherwise they should be calculated relatively to the active application element. | fe50b60b-916d-420b-8728-ee2072ec53eb\nx | number | yes | Horizontal coordinate offset. | 100\ny | number | yes | Vertical coordinate offset. | 100\n\n### mobile: dragFromToForDuration\n\nPerforms drag and drop gesture by coordinates. This can be done either on an element or\non the screen","metadata":{"headerPath":"### mobile: twoFingerTap > #### Examples","sectionCount":5,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: dragFromToForDuration > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to perform drag on. All the coordinates will be calculated relatively this this element position on the screen. Absolute screen coordinates are expected if this argument is not set | fe50b60b-916d-420b-8728-ee2072ec53eb\nduration | number | yes | Float number of seconds in range [0.5, 60]. How long the tap gesture at starting drag point should be before to start dragging | 5.3\nfromX | number | yes | The x coordinate of starting drag point | 100\nfromY | number | yes | The y coordinate of starting drag point | 100\ntoX | number | yes | The x coordinate of ending drag point | 200\ntoY | number | yes | The y coordinate of ending drag point | 200","metadata":{"headerPath":"### mobile: dragFromToForDuration > #### Arguments","sectionCount":1,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: dragFromToForDuration > #### Examples\n\n=== \"Java\"\n\n ```java\n RemoteWebElement e = driver.findElement(AppiumBy.accessibilityId(\"target element\"));\n driver.executeScript(\"mobile: dragFromToForDuration\", ImmutableMap.of(\n \"elementId\", e.getId(),\n \"duration\", 1.0,\n \"fromX\", 100,\n \"fromY\", 100,\n \"toX\", 200,\n \"toY\", 200\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const e = await $('~target element');\n await driver.executeScript('mobile: dragFromToForDuration', [{\n elementId: e.elementId,\n duration: 1.0,\n fromX: 100,\n fromY: 100,\n toX: 200,\n toY: 200\n }]);\n\n=== \"Python\"\n\n ```python\n e = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='target element')\n driver.execute_script(\"mobile: dragFromToForDuration\", {\n \"elementId\": e.id,\n \"duration\": 1.0,\n \"fromX\": 100,\n \"fromY\": 100,\n \"toX\": 200,\n \"toY\": 200\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n e = driver.find_element :accessibility_id, 'target element'\n driver.execute_script 'mobile: dragFromToForDuration', {\n elementId: e.ref,\n duration: 1.0,\n fromX: 100,\n fromY: 100,\n toX: 200,\n toY: 200\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n var e = driver.FindElement(By.AccessibilityId(\"target element\"))\n driver.ExecuteScript(\"mobile: dragFromToForDuration\", new Dictionary<string, object>() {\n {\"elementId\", element.Id},\n {\"duration\", 1.0,}\n {\"fromX\", 100},\n {\"fromY\", 100},\n {\"toX\", 200},\n {\"toY\", 200}\n });\n ```\n\n### mobile: dragFromToForDuration > #### Reference\n\n[clickForDuration:thenDragToElement:](https://developer.apple.com/documentation/xctest/xcuielement/1500989-clickforduration?language=objc)\n\n### mobile: dragFromToWithVelocity\n\nInitiates a press-and-hold gesture, drags to another coordinate or an element with a velocity you specify, and holds for a duration you specify.","metadata":{"headerPath":"### mobile: dragFromToForDuration > #### Examples","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: dragFromToWithVelocity > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nfromElementId | string | no | The internal element identifier (as hexadecimal hash string) to start the drag gesture from. Absolute screen coordinates are expected if this argument is not set | fe50b60b-916d-420b-8728-ee2072ec53eb\ntoElementId | string | no | The internal element identifier (as hexadecimal hash string) to end the drag gesture on. This parameter is mandatory if `fromElementId` is provided | fe50b60b-916d-420b-8728-ee2072ec53eb\npressDuration | number | yes | Float number of seconds in range [0, 60]. How long the tap gesture at starting drag point should be before to start dragging | 0.5\nholdDuration | number | yes | Float number of seconds in range [0, 60]. The duration for which to hold over the other coordinate or the given element after dragging | 0.1\nvelocity | number | yes | The speed at which to move from the initial press position to the other element or coordinate, expressed in pixels per second | 400\nfromX | number | no | The x coordinate of starting drag point. Must be provided if `fromElementId` is not defined | 100\nfromY | number | no | The y coordinate of starting drag point. Must be provided if `fromElementId` is not defined | 100\ntoX | number | no | The x coordinate of ending drag point. Must be provided if `fromElementId` is not defined | 200\ntoY | number | no | The y coordinate of ending drag point. Must be provided if `fromElementId` is not defined | 200\n\n### mobile: dragFromToWithVelocity > #### References\n\n[pressForDuration:thenDragToElement:withVelocity:thenHoldForDuration:](https://developer.apple.com/documentation/xctest/xcuielement/3551693-pressforduration?language=objc)\n[pressForDuration:thenDragToCoordinate:withVelocity:thenHoldForDuration:](https://developer.apple.com/documentation/xctest/xcuicoordinate/3551692-pressforduration?language=objc)\n\n### mobile: rotateElement\n\nPerforms [rotate](https://developer.apple.com/documentation/xctest/xcuielement/1618665-rotate?language=objc) gesture on the given element.","metadata":{"headerPath":"### mobile: dragFromToWithVelocity > #### Arguments","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: rotateElement > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | Internal element id (as hexadecimal hash string) to perform rotation on. The active application element will be used instead if this parameter is not provided. | fe50b60b-916d-420b-8728-ee2072ec53eb\nrotation | number | yes | The rotation of the gesture in radians | Math.PI\nvelocity | number | yes | The velocity of the rotation gesture in radians per second | Math.PI / 4\n\n### mobile: rotateElement > #### Examples\n\n=== \"Java\"\n\n ```java\n RemoteWebElement e = driver.findElement(AppiumBy.accessibilityId(\"target element\"));\n driver.executeScript(\"mobile: rotateElement\", ImmutableMap.of(\n // rotate clockwise, 90 degrees\n \"rotation\", -Math.PI / 2,\n // in approximately two seconds\n \"velocity\", Math.PI / 4,\n \"elementId\", e.getId()\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const e = await $('~target element');\n await driver.executeScript('mobile: rotateElement', [{\n rotation: -Math.PI / 2,\n velocity: Math.PI / 4,\n elementId: e.elementId\n }]);\n ```\n\n=== \"Python\"\n\n ```python\n e = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='target element')\n driver.execute_script(\"mobile: rotateElement\", {\n \"rotation\": -math.pi / 2,\n \"velocity\": math.pi / 4,\n \"elementId\": e.id\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n e = driver.find_element :accessibility_id, 'target element'\n driver.execute_script 'mobile: rotateElement', {\n elementId: e.ref,\n rotation: PI / 2,\n velocity: PI / 4\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n var e = driver.FindElement(By.AccessibilityId(\"target element\"))\n driver.ExecuteScript(\"mobile: rotateElement\", new Dictionary<string, object>() {\n {\"elementId\", element.Id},\n {\"rotation\", -Math.PI / 2 },\n {\"velocity\", Math.PI / 4 },\n });\n ```\n\n### mobile: rotateElement > #### Reference\n\n[rotate:withVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/1618665-rotate?language=objc)\n\n### mobile: tapWithNumberOfTaps\n\nSends one or more taps with one or more touch points since Appium 1.17.1.","metadata":{"headerPath":"### mobile: rotateElement > #### Arguments","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: tapWithNumberOfTaps > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId (\"element\" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to perform one or more taps. The active application element will be used instead if this parameter is not provided.| fe50b60b-916d-420b-8728-ee2072ec53eb\nnumberOfTaps | number | no | The number of taps. 1 by default | 2\nnumberOfTouches | number | no | The number of touch points. 1 by default | 2\n\n### mobile: tapWithNumberOfTaps > #### Examples\n\n=== \"Java\"\n\n ```java\n RemoteWebElement e = driver.findElement(AppiumBy.accessibilityId(\"target element\"));\n var result = driver.executeScript(\"mobile: tapWithNumberOfTaps\", Map.of(\n \"elementId\", e.getId(),\n \"numberOfTaps\", 2,\n \"numberOfTouches\", 1,\n ));\n ```\n\n=== \"JS (WebdriverIO)\"\n\n ```js\n const e = await $('~target element');\n await driver.executeScript('mobile: tapWithNumberOfTaps', [{\n elementId: e.elementId,\n numberOfTaps: 2,\n numberOfTouches: 1\n }]);\n ```\n\n=== \"Python\"\n\n ```python\n e = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='target element')\n driver.execute_script(\"mobile: tapWithNumberOfTaps\", {\n \"elementId\": e.id,\n \"numberOfTaps\": 2,\n \"numberOfTouches\": 1\n })\n ```\n\n=== \"Ruby\"\n\n ```ruby\n e = driver.find_element :accessibility_id, 'target element'\n driver.execute_script 'mobile: tapWithNumberOfTaps', {\n elementId: e.ref,\n numberOfTaps: 2,\n numberOfTouches: 1\n }\n ```\n\n=== \"C#\"\n\n ```csharp\n var e = driver.FindElement(By.AccessibilityId(\"target element\"))\n driver.ExecuteScript(\"mobile: touchAndHold\", new Dictionary<string, object>() {\n {\"elementId\", element.Id},\n {\"numberOfTaps\", 2 },\n {\"numberOfTouches\", 1 },\n });\n ```\n\n- numberOfTaps=1, numberOfTouches=1 -> \"vanilla\" single tap\n- numberOfTaps=2, numberOfTouches=1 -> double tap\n- numberOfTaps=3, numberOfTouches=1 -> triple tap\n- numberOfTaps=2, numberOfTouches=2 -> double tap with two fingers\n\n### mobile: tapWithNumberOfTaps > #### Reference\n\n[tapWithNumberOfTaps:numberOfTouches:](https://developer.apple.com/documentation/xctest/xcuielement/1618671-tapwithnumberoftaps)\n\n### mobile: forcePress\n\nEmulates force press on the given element/coordinates.\nAn error is thrown if the target device does not support force press gesture.","metadata":{"headerPath":"### mobile: tapWithNumberOfTaps > #### Arguments","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: forcePress > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId | string | no | The internal element identifier (as hexadecimal hash string) to perform one or more taps. It is expected that both x and y are provided if this argument is omitted. If the element identifier is provided without coordinates then the actual element's touch point will be calculated automatically by WebDriverAgent. | fe50b60b-916d-420b-8728-ee2072ec53eb\nx | number | no | x coordinate of the gesture. It is calculated relatively to the given element (if provided). Otherwise the gesture destination point is calculated relatively to the active application. | 100\ny | number | no | y coordinate of the gesture. It is calculated relatively to the given element (if provided). Otherwise the gesture destination point is calculated relatively to the active application | 100\nduration | number | no | The float number of seconds the force press action would take. If duration is provided then it is also expected that a custom pressure value is provided as well. `0.5` by default. | 2.5\npressure | number | no | The float number defining how much pressure to apply. If pressure is provided then it is also expected that a custom duration value is provided as well. `1.0` by default | 1.5\n\n### mobile: scrollToElement\n\nScrolls the current viewport to the given element. It is expected the destination element is inside a scrollable container and is hittable. The scroll direction is detected automatically.\nThis API uses native XCTest calls, so it performs scrolling pretty fast. The same native call is\nimplicitly performed by a vanilla `click` API if the destination element is out of the current viewport. An exception is thrown if the scrolling action cannot be performed.\nThis extension is available since the driver version 4.7.0.\n\n### mobile: scrollToElement > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId | string | yes | The internal element identifier (as hexadecimal hash string) to scroll to. The destination element must be located in a scrollable container and must be hittable. If the element is already present in the current viewport then no action is performed. | fe50b60b-916d-420b-8728-ee2072ec53eb","metadata":{"headerPath":"### mobile: forcePress > #### Arguments","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: resetLocationService\n\nReset the location service on real device since Appium 1.22.0.\nIt take a few seconds to reflect the new location by the system.\nThe API raises an error if the device is simulator or an\nunexpected error has occurred on iOS version below 17.\nOn iOS 17+ it is an alias to [mobile: resetSimulatedLocation](#mobile-resetsimulatedlocation).\n\n### mobile: enableConditionInducer\n\nImportant: Device conditions are available for real devices running iOS 13.0 and later.\n\nThis API is going to throw an error if it is called while another condition inducer has been already enabled and is not explicitly disabled.\n\n```\nmobile: enableConditionInducer\nmobile: disableConditionInducer\nmobile: listConditionInducers\n```\n\nThe above three extensions are available since the driver version 4.9.0.\n\nYou can create a condition on a connected device to test your app under adverse conditions, such as poor network connectivity or thermal constraints.\n\nWhen you start a device condition, the operating system on the device behaves as if its environment has changed. The device condition remains active until you stop the device condition or disconnect the device. For example, you can start a device condition, run your app, monitor your app's energy usage, and then stop the condition.\n\nReference: [Test under adverse device conditions (iOS)](https://help.apple.com/xcode/mac/current/#/dev308429d42)\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nconditionID | string | yes | Get the conditionID parameter through the command `mobile: availableConditionInducer` | SlowNetworkCondition\nprofileID | string | yes | Get the profileID parameter through the command `mobile: availableConditionInducer` | SlowNetwork100PctLoss\n\n### mobile: enableConditionInducer > #### Returned Result\n\nEither `true` or `false`, where `true` means enabling of the condition inducer has been successful\n\n### mobile: listConditionInducers\n\nGet all condition inducer configuration profiles","metadata":{"headerPath":"### mobile: resetLocationService","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: listConditionInducers > #### Returned Result\n\nThe response looks like\n\n```\n[{\n \"profiles\": [\n {\n \"name\": \"100% packet loss\",\n \"identifier\": \"SlowNetwork100PctLoss\", // enableConditionInducer profileID\n \"description\": \"Name: 100% Loss Scenario\n Downlink Bandwidth: 0 Mbps\n Downlink Latency: 0 ms\n Downlink Packet Loss Ratio: 100%\n Uplink Bandwidth: 0 Mbps\n Uplink Latency: 0 ms\n Uplink Packet Loss Ratio: 100%\"\n },\n ],\n \"profilesSorted\": true,\n \"identifier\": \"SlowNetworkCondition\", // enableConditionInducer conditionID\n \"isDestructive\": false,\n \"isInternal\": false,\n \"activeProfile\": \"\",\n \"name\": \"Network Link\",\n \"isActive\": false\n}]\n```\n\n### mobile: disableConditionInducer\n\nDisable device condition inducer.\n\nUsually a persistent connection is maintained after enable the condition inducer, and this method is only valid for this connection.\n\nIf the connection is disconnected, condition inducer will be automatically disabled\n\n### mobile: disableConditionInducer > #### Returned Result\n\nEither `true` or `false`, where `true` means disabling of the condition inducer has been successful\n\n### mobile: calibrateWebToRealCoordinatesTranslation\n\nCalibrates web to real coordinates translation.\nThis API can only be called from Safari web context.\nIt must load a custom page to the browser, and then restore\nthe original one, so don't call it if you can potentially\nlose the current web app state.\nThe outcome of this API is then used if `nativeWebTap` capability/setting is enabled.\nThe returned value could also be used to manually transform web coordinates\nto real device ones in client scripts.\n\nIt is advised to call this API at least once before changing the device orientation\nor device screen layout as the recetly received value is cached for the session lifetime\nand may become obsolete.\n\nIt is advised to enable `nativeWebTapStrict` capability/setting to speed up dynamic coordinates\ntransformation if you use this extension.","metadata":{"headerPath":"### mobile: listConditionInducers > #### Returned Result","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: calibrateWebToRealCoordinatesTranslation > #### Returned Result\n\nAn object with three properties used to properly shift Safari web element coordinates into native context:\n- `offsetX`: Webview X offset in real coordinates\n- `offsetY`: Webview Y offset in real coordinates\n- `pixelRatioX`: Webview X pixel ratio\n- `pixelRatioY`: Webview Y pixel ratio\n\nThe following formulas are used for coordinates translation:\n`RealX = offsetX + webviewX * pixelRatioX`\n`RealY = offsetY + webviewY * pixelRatioY`\n\n### mobile: updateSafariPreferences\n\nUpdates preferences of Mobile Safari on Simulator\n\n### mobile: updateSafariPreferences > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\npreferences | map | yes | An object containing Mobile Safari preferences to be updated. The list of available setting names and their values could be retrieved by changing the corresponding Safari settings under Preferences-&gt;Safari and then inspecting `Library/Preferences/com.apple.mobilesafari.plist` file inside of `com.apple.mobilesafari` app container. The full path to the Mobile Safari's container could be retrieved from `xcrun simctl get_app_container <sim_udid> com.apple.mobilesafari data` command output. Use the `xcrun simctl spawn <sim_udid> defaults read <path_to_plist>` command to print the actual .plist content to the Terminal. | { ShowTabBar: 0, WarnAboutFraudulentWebsites: 0 }\n\n### mobile: deepLink\n\nOpens the given URL with the default or the given application.\nThis functionality is only available since xcuitest driver version 4.17.\nXcode must be at version 14.3+ and iOS must be at version 16.4+.\n\n### mobile: deepLink > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nurl | string | yes | The URL to be opened. This parameter is manadatory. | https://apple.com, myscheme:yolo\nbundleId | string | no | The bundle identifier of an application to open the given url with. If not provided then the default application for the given url scheme is going to be used. | com.myapp.yolo\n\n### mobile: getSimulatedLocation\n\nRetrieves simulated geolocation value.\nThis functionality is only available since xcuitest driver version 4.18.\nXcode must be at version 14.3+ and iOS must be at version 16.4+.","metadata":{"headerPath":"### mobile: calibrateWebToRealCoordinatesTranslation > #### Returned Result","sectionCount":6,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: getSimulatedLocation > #### Returned Result\n\nThis API returns a map with the following entries:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nlatitude | number | Measurement of distance north or south of the Equator. `null` if [mobile: setSimulatedLocation](#mobile-setsimulatedlocation) has not been called before or the simulated geolocation has been reset by [mobile: resetSimulatedLocation](#mobile-resetsimulatedlocation). | 50.08546\nlongitude | number | Measurement of distance east or west of the prime meridian. `null` if [mobile: setSimulatedLocation](#mobile-setsimulatedlocation) has not been called before or the simulated geolocation has been reset by [mobile: resetSimulatedLocation](#mobile-resetsimulatedlocation). | -20.12345\n\n### mobile: setSimulatedLocation\n\nSets simulated geolocation value.\nThis functionality is only available since xcuitest driver version 4.18.\nXcode must be at version 14.3+ and iOS must be at version 16.4+.\n\nIt is recommended for iOS 17+ real devices to simulate the device location.\n\n### mobile: setSimulatedLocation > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nlatitude | number | yes | Measurement of distance north or south of the Equator. | 50.08546\nlongitude | number | yes | Measurement of distance east or west of the prime meridian. | -20.12345\n\n### mobile: resetSimulatedLocation\n\nResets the previously set simulated geolocation value.\nThis functionality is only available since xcuitest driver version 4.18.\nXcode must be at version 14.3+ and iOS must be at version 16.4+.\n\n> **Warning**\n> Do not forget to reset the simulated geolocation value after your automated test is finished.\n> If the value is not reset explicitly then the simulated one will remain until the next device restart.\n\n### mobile: getAppStrings\n\nRetrieves string resources for the given app language. An error is thrown if strings cannot be fetched or no strings exist\nfor the given language abbreviation\n\n### mobile: getAppStrings > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nlanguage | string | no | The language abbreviation to fetch app strings mapping for. If no language is provided then strings for the 'en language would be returned | fr\nstringFile | string | no | Relative path to the corresponding .strings file starting from the corresponding .lproj folder | base/main.strings","metadata":{"headerPath":"### mobile: getSimulatedLocation > #### Returned Result","sectionCount":6,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: getAppStrings > #### Returned Result\n\nApp strings map, where keys are resource identifiers.\n\n### mobile: hideKeyboard\n\nTries to hide the on-screen keyboard. Throws an exception if the keyboard cannot be hidden. On non-tablet devices the keyboard might not have an explicit button to hide it. In such case this API won't work and the only way to close the keyboard would be to simulate the same action an app user would do to close it. For example, swipe from top to bottom or tap the screen somewhere at the area not covered by the keyboard.\n\n### mobile: hideKeyboard > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nkeys | string[] | no | One or more keyboard key names used to close/hide it. On tablet's such button is usually called 'done'.\n\n### mobile: isKeyboardShown\n\nChecks if the system on-screen keyboard is visible.\n\n### mobile: isKeyboardShown > #### Returned Result\n\n`true` if the keyboard is visible\n\n### mobile: keys\n\nSend keys to the given element or to the application under test.\nThis API is only supported since Xcode 15/iOS 17.\nIt is not supported on tvOS.\nThe API only works on iPad. On iOS calling it has no effect.","metadata":{"headerPath":"### mobile: getAppStrings > #### Returned Result","sectionCount":6,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: keys > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nelementId | string | no | Unique identifier of the element to send the keys to. If unset then keys are sent to the current application under test. | 21045BC8-013C-43BD-9B1E-4C6DC7AB0744\nkeys | array | yes | Array of keys to type. Each item could either be a string, that represents a key itself (see the official documentation on XCUIElement's [typeKey:modifierFlags: method](https://developer.apple.com/documentation/xctest/xcuielement/1500604-typekey?language=objc) and on [XCUIKeyboardKey constants](https://developer.apple.com/documentation/xctest/xcuikeyboardkey?language=objc)) or a dictionary with `key` and `modifierFlags` entries, if the key should also be entered with modifiers. | ['h', 'i'] or [{key: 'h', modifierFlags: 1 << 1}, {key: 'i', modifierFlags: 1 << 2}] or ['XCUIKeyboardKeyEscape'] |\n\n!!! note\n\n The `modifierFlags` argument is of `unsigned long` type and defines the bitmask with depressed modifier keys for the given key.\n XCTest defines the following possible bitmasks for modifier keys:\n\n <pre>\n typedef NS_OPTIONS(NSUInteger, XCUIKeyModifierFlags) {\n XCUIKeyModifierNone = 0,\n XCUIKeyModifierCapsLock = (1UL << 0),\n XCUIKeyModifierShift = (1UL << 1),\n XCUIKeyModifierControl = (1UL << 2),\n XCUIKeyModifierOption = (1UL << 3),\n XCUIKeyModifierCommand = (1UL << 4),\n XCUIKeyModifierFunction = (1UL << 5),\n // These values align with UIKeyModifierFlags and CGEventFlags.\n XCUIKeyModifierAlphaShift = XCUIKeyModifierCapsLock,\n XCUIKeyModifierAlternate = XCUIKeyModifierOption,\n };\n </pre>\n\n So, for example, if you want Ctrl and Shift to be depressed while entering your key then `modifierFlags` should be set to\n `(1 << 1) | (1 << 2)`, where the first constant defines `XCUIKeyModifierShift` and the seconds\n one - `XCUIKeyModifierControl`. We apply the [bitwise or](https://www.programiz.com/c-programming/bitwise-operators#or)\n (`|`) operator between them to raise both bitflags\n in the resulting value. The [left bitshift](https://www.programiz.com/c-programming/bitwise-operators#left-shift)\n (`<<`) operator defines the binary bitmask for the given modifier key.\n You may combine more keys using the same approach.","metadata":{"headerPath":"### mobile: keys > #### Arguments","sectionCount":1,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: lock\n\nLock the device (and optionally unlock it after a certain amount of time). Only simple (e.g. without a password) locks are supported.\n\n### mobile: lock > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nseconds | number|string | no | The number of seconds after which to unlock the device. Set to `0` or leave it empty to require manual unlock (e.g. do not block and automatically unlock afterwards). | 5\n\n### mobile: unlock\n\nUnlocks the previously locked device. Only simple (e.g. without a password) locks are supported.\n\n### mobile: isLocked\n\nDetermine whether the device is locked.\n\n### mobile: isLocked > #### Returned Result\n\nEither `true` or `false`\n\n### mobile: shake\n\nShakes the device. This functionality is only supported on simulators.\n\n### mobile: backgroundApp\n\nPuts the app to the background and waits the given number of seconds. Then restores the app\nif necessary. The call is blocking.\n\n### mobile: backgroundApp > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nseconds | number | no | The amount of seconds to wait between putting the app to background and restoring it. Any negative value means to not restore the app after putting it to background (the default behavior). | 5\n\n### mobile: performAccessibilityAudit\n\nPerforms accessibility audit of the current application according to the given type or multiple types.\nWraps the XCTest's [performAccessibilityAuditWithAuditTypes](https://developer.apple.com/documentation/xctest/xcuiapplication/4190847-performaccessibilityauditwithaud?language=objc) API.\nOnly available since Xcode 15/iOS 17.\n\n### mobile: performAccessibilityAudit > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nauditTypes | string[] | no | One or more type names to perform the audit for. The full list of available names could be found in the official [XCTest API documentation](https://developer.apple.com/documentation/xctest/xcuiaccessibilityaudittype?language=objc). If no type if provided explicitly then `XCUIAccessibilityAuditTypeAll` is assumed. | ['XCUIAccessibilityAuditTypeContrast', 'XCUIAccessibilityAuditTypeElementDetection']","metadata":{"headerPath":"### mobile: lock","sectionCount":10,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: performAccessibilityAudit > #### Returned Result\n\nList of found issues or an empty list. Each list item is a map consisting of the following items:\n\nName | Type | Description | Example\n--- | --- | --- | ---\ndetailedDescription | string | The detailed description of the found accessibility issue. | Some longer issue description\ncompactDescription | string | The compact description of the found accessibility issue. | Some compact issue description\nauditType | string or number | The name of the audit type this issue belongs to. Could be a number if the type name is unknown. | 'XCUIAccessibilityAuditTypeContrast'\nelement | string | The description of the element this issue was found for. | 'Yes' button\nelementDescription | string | The debug description of the element this issue was found for. Available since driver version | A long string describing the element itself and its position in the page tree hierarchy\nelementAttributes | dict | JSON object containing various attributes of the element. | See the example below\n\n```json\n\"elementAttributes\":{\n \"isEnabled\":\"1\",\n \"isVisible\":\"1\",\n \"isAccessible\":\"0\",\n \"frame\":\"{{129, 65}, {135, 18}}\",\n \"isFocused\":\"0\",\n \"rect\":{\n \"y\":65,\n \"x\":129,\n \"width\":135,\n \"height\":18\n },\n \"value\":\"Some Button\",\n \"label\":\"Some Button\",\n \"type\":\"StaticText\",\n \"name\":\"Some Button\",\n \"rawIdentifier\":null\n}\n```\n\n### mobile: startXCTestScreenRecording\n\nStart a new screen recording via XCTest.\n\nSince this feature is based on the native implementation provided by Apple\nit provides the best quality for the least performance penalty in comparison\nto alternative implementations.\n\nEven though the feature is available for real devices\nthere is no possibility to delete video files stored on the device yet,\nwhich may lead to internal storage overload.\nThat is why it was put under the `xctest_screen_record` security\nfeature flag if executed from a real device test.\n\nIf the screen recording is already running this API is a noop.\n\nThe feature is only available since Xcode 15/iOS 17.\n\n### mobile: startXCTestScreenRecording > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nfps | number | no | The Frames Per Second value for the resulting video. Providing higher values will create video files that are greater in size, but with smoother transitions. It is highly recommended to keep this value is range 1-60. 24 by default | 60","metadata":{"headerPath":"### mobile: performAccessibilityAudit > #### Returned Result","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: startXCTestScreenRecording > #### Returned Result\n\nThe API response consists of the following entries:\n\nName | Type | Description | Example\n--- | --- | --- | ---\nuuid | string | Unique identifier of the video being recorded | 1D988774-C7E2-4817-829D-3B835DDAA7DF\nfps | number | FPS value | 24\ncodec | number | The magic for the used codec. Value of zero means h264 video codec is being used | 0\nstartedAt | number | The timestamp when the screen recording has started in float seconds since Unix epoch | 1709826124.123\n\n### mobile: getXCTestScreenRecordingInfo\n\nRetrieves information about the current running screen recording.\nIf no screen recording is running then `null` is returned.\n\n### mobile: getXCTestScreenRecordingInfo > #### Returned Result\n\nSame as for [mobile: startXCTestScreenRecording](#mobile-startxctestscreenrecording)\n\n### mobile: stopXCTestScreenRecording\n\nStops the current XCTest screen recording previously started by the\n[mobile: startXctestScreenRecording](#mobile-startxctestscreenrecording) API.\n\nAn error is thrown if no screen recording is running.\n\nThe resulting movie is returned as base-64 string or is uploaded to\na remote location if corresponding options have been provided.\n\nThe resulting movie is automatically deleted from the local file system **FOR SIMULATORS ONLY**.\nIn order to clean it up from a real device it is necessary to properly\nshut down XCTest by calling `GET /wda/shutdown` API to the WebDriverAgent server running\non the device directly or by doing device factory reset.","metadata":{"headerPath":"### mobile: startXCTestScreenRecording > #### Returned Result","sectionCount":4,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: stopXCTestScreenRecording > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\nremotePath | string | no | The path to the remote location, where the resulting .mov file should be uploaded. The following protocols are supported: http/https, ftp Null or empty string value (the default setting) means the content of resulting file should be encoded as Base64 and passed to the endpoint response value. An exception will be thrown if the generated file is too big to fit into the available process memory. | https://myserver/upload\nuser | string | no | The name of the user for the remote authentication. Only works if `remotePath` is provided. | myuser\npass | string | no | The password for the remote authentication. Only works if `remotePath` is provided. | mypassword\nmethod | string | no | The http multipart upload method name. Only works if `remotePath` is provided. `PUT` by default | POST\nheaders | dict | no | Additional headers mapping for multipart http(s) uploads | {'User-Agent': 'Myserver 1.0'}\nfileFieldName | string | no | The name of the form field, where the file content BLOB should be stored for http(s) uploads. `file` by default | payload\nformFields | dict or array | no | Additional form fields for multipart http(s) uploads | {'field2': 'value2'}\n\n### mobile: stopXCTestScreenRecording > #### Returned Result\n\nSame as for [mobile: startXCTestScreenRecording](#mobile-startxctestscreenrecording) plus the below entry:\n\nName | Type | Description | Example\n--- | --- | --- | ---\npayload | string | Base64-encoded content of the recorded media file if `remotePath` parameter is empty/null or an empty string otherwise. The resulting media is expected to a be a valid QuickTime movie (.mov). | `YXBwaXVt....`\n\n### mobile: simctl\n\nRuns the given command as a subcommand of `xcrun simctl` against the device under test.\nDoes not work for real devices.","metadata":{"headerPath":"### mobile: stopXCTestScreenRecording > #### Arguments","sectionCount":3,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"### mobile: simctl > #### Arguments\n\nName | Type | Required | Description | Example\n--- | --- | --- | --- | ---\ncommand | string | yes | a subcommand for the `simctl`. Available commands are boot, get_app_container, getenv, icloud_sync, install, install_app_data, io, keychain, launch, location, logverbose, openurl, pbcopy, pbpaste, privacy, push, shutdown, spawn, status_bar, terminate, ui, and uninstall. Please check each usage details with `xcrun simctl help`. | `'getenv'`\nargs | array | no | array of string as arguments for the command after `<device>`. For example `getenv` subcommand accept `simctl getenv <device> <variable name>`. The `<device>` will be filled out automatically. This `args` should be the ` <variable name>` part only. | `['HOME']`\ntimeout | number | no | Command timeout in milliseconds. If the command blocks for longer than this timeout then an exception is going to be thrown. The default timeout is `600000` ms. | `10000`\n\n### mobile: simctl > #### Returned Result\n\nName | Type | Description | Example\n--- | --- | --- | ---\nstdout | string | The standard output of the command. | `'/Users/user/Library/Developer/CoreSimulator/Devices/60EB8FDB-92E0-4895-B466-0153C6DE7BAE/data\\n'`\nstderr | string | The standard error of the command. | `''` (an empty string)\ncode | string | The status code of the command. | `0`","metadata":{"headerPath":"### mobile: simctl > #### Arguments","sectionCount":2,"filename":"execute-methods.md","relativePath":"appium-xcuitest-driver/docs/reference/execute-methods.md"}},{"pageContent":"---\ntitle: Predicate Locator Strategy\n--- \n\nThe XCUITest driver supports searching elements using the _predicate_ and _class chain_\n[locator search strategies](./locator-strategies.md). They are powered by Apple XCTest, provide\nflexibility and are much faster than XPath. Predicates can be used to restrict a set of elements to\nselect only those for which some condition evaluates to true.\n\n!!! tip\n\n In addition to the examples listed here, make sure to check the links in the\n [More Information](#more-information) section below!\n\n### Quick Examples\n\n=== \"Predicate String\"\n\n ```java\n // java\n driver.findElements(AppiumBy.iOSNsPredicateString(\"isVisible == 1\"));\n ```\n\n=== \"Class Chain\"\n\n ```java\n // java\n driver.findElements(AppiumBy.iOSClassChain(\"**/XCUIElementTypeWindow[`label LIKE '*yolo*'`]\"));\n ```\n\nThe predicate string example would select all visible elements on the page, while the class chain\nexample would find all elements of type `XCUIElementTypeWindow` whose label contains `yolo`. Class\nchain queries allow to create much more complicated search expressions and may contain multiple\npredicates. Check the [More Information](#more-information) section below for how to build such queries.","metadata":{"headerPath":"","sectionCount":2,"filename":"ios-predicate.md","relativePath":"appium-xcuitest-driver/docs/reference/ios-predicate.md"}},{"pageContent":"### Basic Comparisons\n\n* `=` , `==` - The left-hand expression is equal to the right-hand expression:\n ```java\n // java\n driver.findElements(AppiumBy.iOSNsPredicateString(\"label == 'Olivia'\"));\n\n // same in Xpath:\n driver.findElements(AppiumBy.xpath(\"//*[@label = 'Olivia']\"));\n ```\n\n* `>=` , `=>` - The left-hand expression is greater than or equal to the right-hand expression.\n\n* `<=` , `=<` - The left-hand expression is less than or equal to the right-hand expression.\n\n* `>` - The left-hand expression is greater than the right-hand expression.\n\n* `<` - The left-hand expression is less than the right-hand expression.\n\n* `!=` , `<>` - The left-hand expression is not equal to the right-hand expression.\n\n* `BETWEEN` - The left-hand expression is between, or equal to either of, the values specified in\n the right-hand side. The right-hand side is a two value array (an array is required to specify\n order) giving upper and lower bounds. For example, `1 BETWEEN { 0 , 33 }`, or `$INPUT BETWEEN { $LOWER, $UPPER }`.\n In Objective-C, you could create a `BETWEEN` predicate as shown in the following example:\n\n ```java\n driver.findElements(AppiumBy.iOSNsPredicateString(\"rect.x BETWEEN { 1, 100 }\"));\n ```\n\n This creates a predicate that matches all elements whole left top coordinate is in range between\n 1 and 100.\n\n### Boolean Value Predicates\n\n* `TRUEPREDICATE` - A predicate that always evaluates to `TRUE` .\n\n* `FALSEPREDICATE` - A predicate that always evaluates to `FALSE`.\n\n### Basic Compound Predicates\n\n* `AND` , `&&` - Logical AND.\n\n* `OR` , `||` - Logical OR.\n\n* `NOT` , `!` - Logical NOT.","metadata":{"headerPath":"### Basic Comparisons","sectionCount":3,"filename":"ios-predicate.md","relativePath":"appium-xcuitest-driver/docs/reference/ios-predicate.md"}},{"pageContent":"### String Comparisons\n\nString comparisons are by default case and diacritic sensitive. You can modify an operator using the\nkey characters `c` and `d` within square braces to specify case and diacritic insensitivity\nrespectively, for example, `value BEGINSWITH[cd] 'bar'`.\n\n* `BEGINSWITH` - The left-hand expression begins with the right-hand expression.\n\n ```java\n driver.findElement(AppiumBy.iOSNsPredicateString(\"type == 'XCUIElementTypeButton' AND name BEGINSWITH 'results toggle'\"));\n\n // same in Xpath:\n driver.findElement(AppiumBy.xpath(\"//XCUIElementTypeButton[starts-with(@name, 'results toggle')]\"));\n ```\n\n* `CONTAINS` - The left-hand expression contains the right-hand expression.\n\n ```java\n driver.findElement(AppiumBy.iOSNsPredicateString(\"type == 'XCUIElementCollectionView' AND name CONTAINS 'opera'\"));\n\n // same in Xpath:\n driver.findElement(AppiumBy.xpath(\"//XCUIElementCollectionView[contains(@name, 'opera')]\"));\n ```\n\n* `ENDSWITH` - The left-hand expression ends with the right-hand expression.\n\n* `LIKE` - The left hand expression equals the right-hand expression: `?` and `*` are allowed as\n wildcard characters, where `?` matches 1 character and `*` matches 0 or more characters. In Mac\n OS X v10.4, wildcard characters do not match newline characters.\n\n ```java\n driver.findElement(AppiumBy.iOSNsPredicateString(\"name LIKE '*Total: $*'\"));\n\n // XPath1 does not have an alternative to the above expression\n ```\n\n* `MATCHES` - The left hand expression equals the right hand expression using a regex-style\n comparison according to ICU v3 (for more details see the ICU User Guide for\n [Regular Expressions](http://userguide.icu-project.org/strings/regexp)).\n\n ```java\n driver.findElement(AppiumBy.iOSNsPredicateString(\"value MATCHES '.*of [1-9]'\"));\n\n // XPath1 does not have an alternative to the above expression\n ```\n\n### Aggregate Operations\n\n* `IN` - Equivalent to an SQL IN operation, the left-hand side must appear in the collection\n specified by the right-hand side. For example, `name IN { 'Ben', 'Melissa', 'Matthew' }`.\n The collection may be an array, a set, or a dictionary (in the case of a dictionary, its values\n are used).","metadata":{"headerPath":"### String Comparisons","sectionCount":2,"filename":"ios-predicate.md","relativePath":"appium-xcuitest-driver/docs/reference/ios-predicate.md"}},{"pageContent":"### Identifiers\n\n* **C style identifier** - Any C style identifier that is not a reserved word.\n\n* **\\#symbol** - Used to escape a reserved word into a user identifier.\n\n* **[\\\\]{octaldigit}{3}** - Used to escape an octal number ( ```\\``` followed by 3 octal digits).\n\n* **[\\\\][xX]{hexdigit}{2}** - Used to escape a hex number ( ```\\x``` or ```\\X``` followed by 2 hex digits).\n\n* **[\\\\][uU]{hexdigit}{4}** - Used to escape a Unicode number ( ```\\u``` or ```\\U``` followed by 4 hex digits).\n\n### Literals\n\nSingle and double quotes produce the same result, but they do not terminate each other. For example,\n`\"abc\"` and `'abc'` are identical, whereas `\"a'b'c\"` is equivalent to a space-separated\nconcatenation of `a, 'b', c`.\n\n* `FALSE` , `NO` - Logical false.\n\n* `TRUE` , `YES` - Logical true.\n\n* `NULL` , `NIL` - A null value.\n\n* `SELF` - Represents the object being evaluated.\n\n* `\"text\"` - A character string.\n\n* `'text'` - A character string.\n\n* **Comma-separated literal array** - For example, `{ 'comma', 'separated', 'literal', 'array' }` .\n\n* **Standard integer and fixed-point notations** - For example, `1 , 27 , 2.71828 , 19.75` .\n\n* **Floating-point notation with exponentiation** - For example, `9.2e-5` .\n\n* `0x` - Prefix used to denote a hexadecimal digit sequence.\n\n* `0o` - Prefix used to denote an octal digit sequence.\n\n* `0b` - Prefix used to denote a binary digit sequence.\n\n### Reserved Keywords\n\nThe following keywords are reserved:\n\n`AND, OR, IN, NOT, ALL, ANY, SOME, NONE, LIKE, CASEINSENSITIVE, CI, MATCHES, CONTAINS, BEGINSWITH,\nENDSWITH, BETWEEN, NULL, NIL, SELF, TRUE, YES, FALSE, NO, FIRST, LAST, SIZE, ANYKEY, SUBQUERY,\nCAST, TRUEPREDICATE, FALSEPREDICATE`\n\n### Available Attributes\n\nCheck the [Element Attributes](./element-attributes.md) document to know all element attribute\nnames and types that are available for usage in predicate locators.\n\n### More Information\n\n* [Apple Developer documentation on Predicates](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html)\n* [NSPredicate Cheat Sheet](https://academy.realm.io/posts/nspredicate-cheatsheet/)\n* [Class Chain Queries Construction Rules](https://github.com/facebookarchive/WebDriverAgent/wiki/Class-Chain-Queries-Construction-Rules)","metadata":{"headerPath":"### Identifiers","sectionCount":5,"filename":"ios-predicate.md","relativePath":"appium-xcuitest-driver/docs/reference/ios-predicate.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Locator Strategies\n---\n\nThe XCUITest driver supports several location strategies in the native context. The following table\nlists them in performance order (the first one is the fastest one):\n\n| <div style=\"width:14em\">Name</div> | Description | Speed Ranking | Example |\n| --- | --- | --- | --- |\n| `className` | Performs search by element's `type` [attribute](element-attributes.md). The full list of supported XCUIElement type names could be found in the official XCTest [documentation on XCUIElementType](https://developer.apple.com/documentation/xctest/xcuielementtype) | ⭐⭐⭐⭐⭐ | `XCUIElementTypeButton` |\n| `id`, `name`, `accessibility id` | All these locator types are synonyms and internally get transformed into search by element's `name` [attribute](element-attributes.md). | ⭐⭐⭐⭐⭐ | `my name` |\n| `-ios predicate string` | This strategy is mapped to the native XCTest predicate locator. Check the [NSPredicate cheat sheet](https://academy.realm.io/posts/nspredicate-cheatsheet/) for more details on how to build effective predicate expressions. All the supported element [attributes](element-attributes.md) could be used in these expressions. | ⭐⭐⭐⭐⭐ | `(name == 'done' OR value == 'done') AND type IN {'XCUIElementTypeButton', 'XCUIElementTypeKey'}` |\n| `-ios class chain` | This strategy is mapped to the native XCTest predicate locator, but with respect to the actual element tree hierarchy. Such locators are basically a supertype of `-ios predicate string`. Read [Class Chain Queries Construction Rules](https://github.com/facebookarchive/WebDriverAgent/wiki/Class-Chain-Queries-Construction-Rules) for more details on how to build such locators. | ⭐⭐⭐⭐ | ```**/XCUIElementTypeCell[$name == 'done' OR value == 'done'$]/XCUIElementTypeButton[-1]``` |\n| `xpath` | For elements lookup using the Xpath strategy the driver uses the same XML tree that is generated by the page source API. This means such locators are the slowest (sometimes up to 10x slower) in comparison to the ones above, which all depend on native XCTest primitives, but are the most flexible. Use Xpath locators only if there is no other way to locate the given element. Only Xpath 1.0 is supported. | ⭐⭐ | `//XCUIElementTypeButton[@value=\\\"Regular\\\"]/parent::*` |\n\nAlso, consider checking the [How To Achieve The Best Lookup Performance](https://github.com/facebookarchive/WebDriverAgent/wiki/How-To-Achieve-The-Best-Lookup-Performance) article.","metadata":{"headerPath":"","sectionCount":1,"filename":"locator-strategies.md","relativePath":"appium-xcuitest-driver/docs/reference/locator-strategies.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Scripts\n---\n\nAppium drivers can include scripts for executing specific actions. The following table lists the\nscripts bundled with the XCUITest driver. These scripts can be run as follows:\n\n```\nappium driver run xcuitest <script-name>\n```","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"scripts.md","relativePath":"appium-xcuitest-driver/docs/reference/scripts.md"}},{"pageContent":"```\nappium driver run xcuitest <script-name>\n```\n\n|Script Name|Description|\n|------------|-----------|\n|`open-wda`|Opens the WebDriverAgent project in Xcode|\n|`build-wda`|Builds the WebDriverAgent project using the first available iPhone simulator and the latest iOS supported by the current Xcode version by default|\n|`build-wda --sdk=17.5 --name=\"iPhone 15\"`|Builds the WebDriverAgent project using the iPhone 15 simulator with iOS 17.5. If `--sdk` and `--name` params are not specified - the latest iOS and the first available iPhone simulator will be used|\n|`tunnel-creation`|Creates tunnels for connected iOS devices, starts CoreDeviceProxy, and sets up a tunnel registry server. Requires sudo access to communicate with iOS devices|\n|`tunnel-creation --udid=<device-udid>` or `-u <device-udid>`|Creates a tunnel for a specific iOS device with the given UDID|\n|`tunnel-creation --packet-stream-base-port=<port>`|Specifies the base port for packet stream servers (default: 50000)|\n|`tunnel-creation --tunnel-registry-port=<port>`|Specifies the port for the tunnel registry server (default: 42314)|\n|`download-wda-sim --outdir=/path/to/dir`|Download corresponding version's prebuilt WDA for iOS matched with the host machine architecture from [GitHub WebDriver release page](https://github.com/appium/WebDriverAgent/releases) into `--outdir` directory. The downloaded package name will be `WebDriverAgentRunner-Runner.app`.|\n|`download-wda-sim --platform=tvos --outdir=/path/to/dir`|Download corresponding version's prebuilt WDA for `--platform` into `--outdir` directory. If `--platform=tvos` is provided, the download module will be for tvOS (`WebDriverAgentRunner_tvOS-Runner.app`), otherwise the command will download iOS.|\n|`image-mounter mount --image <path> --manifest <path> --trustcache <path>`|Mount a Personalized Developer Disk Image on an iOS device. Requires paths to the .dmg image file, BuildManifest.plist, and .trustcache file. Requires the `appium-ios-remotexpc` optional dependency.|\n|`image-mounter mount --image <path> --manifest <path> --trustcache <path> --udid <device-udid>`|Mount a Developer Disk Image on a specific iOS device with the given UDID|\n|`image-mounter unmount`|Unmount a Developer Disk Image from the first available iOS device (default mount path: `/System/Developer`)|\n|`image-mounter unmount --udid <device-udid>`|Unmount a Developer Disk Image from a specific iOS device with the given UDID|","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"scripts.md","relativePath":"appium-xcuitest-driver/docs/reference/scripts.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Security Feature Flags\n---\n\nSome insecure driver features are disabled by default. They can be enabled upon launching Appium as follows:\n```\nappium --allow-insecure <feature-name>\n```\nor\n```\nappium --relaxed-security\n```\n\n|Feature Name|Description|\n|------------|-----------|\n|`shutdown_other_sims`|Allow any session to use a capability to shutdown any running simulators on the host|\n|`perf_record`|Allow recording the system performance and other metrics of the simulator|\n|`audio_record`|Allow recording of host audio input(s)|\n|`customize_result_bundle_path`|Allow customizing the paths to result bundles, using the `resultBundlePath` capability|","metadata":{"headerPath":"","sectionCount":1,"filename":"security-flags.md","relativePath":"appium-xcuitest-driver/docs/reference/security-flags.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Appium Server Arguments\n---\n\nSome driver arguments can be set when launching the Appium server. This can be done as follows:\n\n```\nappium --driver-xcuitest-[argName]=[argValue]\n```\n\n|Argument|Description|Default|Example|\n|----|-------|-----------|-------|\n| `webdriveragent-port` | Local port used for communicating with WebDriverAgent | `8100` | `--driver-xcuitest-webdriveragent-port=8200` |","metadata":{"headerPath":"","sectionCount":1,"filename":"server-args.md","relativePath":"appium-xcuitest-driver/docs/reference/server-args.md"}},{"pageContent":"---\nhide:\n - toc\n\ntitle: Settings\n---\n\nThe XCUITest driver supports Appium's [Settings API](https://appium.io/docs/en/latest/guides/settings/).\nAlong with the common settings, the following driver-specific settings are available:","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}},{"pageContent":"| <div style=\"width:14em\">Name</div> | Type | Description |\n| --- | --- | --- |\n| `elementResponseAttributes` | `string` | Comma-separated list of element attribute names to be included into findElement response. By default only element UUID is present there, but it is also possible to add the following items: `name`, `text`, `rect`, `enabled`, `displayed`, `selected`, `attribute/<element_attribute_name>`. It is required that `shouldUseCompactResponses` setting is set to `false` in order for this one to apply. |\n| `shouldUseCompactResponses` | `boolean` | Used in combination with `elementResponseAttributes` setting. If set to `false` then the findElement response is going to include the items enumerated in `elementResponseAttributes` setting. `true` by default |\n| `screenshotQuality` | `int` | See the description of the corresponding capability. |\n| `mjpegServerFramerate` | `int` | The maximum count of screenshots per second taken by the MJPEG screenshots broadcaster. Must be in range 1..60. `10` by default |\n| `mjpegScalingFactor` | `float` | The percentage value used to apply downscaling on the screenshots generated by the MJPEG screenshots broadcaster. Must be in range 1..100. `100` is by default, which means that screenshots are not downscaled. |\n| `mjpegServerScreenshotQuality` | `int` | The percentage value used to apply lossy JPEG compression on the screenshots generated by the MJPEG screenshots broadcaster. Must be in range 1..100. `25` is by default, which means that screenshots are compressed to the quarter of their original quality. |\n| <s>`customSnapshotTimeout`</s> | `float` | *Removed since XCUITest driver v8.0.0*. Set how much time in float seconds is allowed to resolve a single accessibility snapshot with custom attributes. _Snapshots_ are mainly used for page source generation, XML lookup and custom attributes retrieval (these are visibility and accessibility ones). It might be necessary to increase this value if the actual page source is very large and contains hundreds of UI elements. Defaults to 15 seconds. Since Appium 1.19.1 if this timeout expires and no custom snapshot could be made then WDA tries to calculate the missing attributes using its own algorithms, so setting this value to zero might speed up, for example, page source retrieval, but for the cost of preciseness of some element attributes. |\n| `waitForIdleTimeout` | `float` | Has the same meaning as corresponding capability (see above) |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}},{"pageContent":"| `waitForIdleTimeout` | `float` | Has the same meaning as corresponding capability (see above) |\n| `animationCoolOffTimeout` | `float` | The amount of time in float seconds to wait until the application under test does not have any active animations. This check is usually applied after each automation action that is supposed to change the state of the application under test, like `click` one, and blocks XCTest until the transition of the tested application to a new state completes or the cool off timeout occurs. The default value is `2` (seconds). Setting it to zero disables animation checks completely. |\n| `snapshotMaxDepth` | `int` | Changes the value of maximum depth for traversing elements source tree. It may help to prevent out of memory or timeout errors while getting the elements source tree, but it might restrict the depth of source tree. Please consider restricting this value if you observed an error like _Timed out snapshotting com.apple.testmanagerd..._ message or _Cannot get 'xml' source of the current application_ in your Appium log since they are possibly timeout related. A part of elements source tree might be lost if the value was too small. Defaults to `50` |\n| `useFirstMatch` | `boolean` | Enabling this setting makes single element lookups faster, but there is the known [problem](https://github.com/appium/appium/issues/10101) related to nested elements lookup. Defaults to `false`. |\n| `reduceMotion` | `boolean` | Changes the 'reduce motion' preference of accessibility feature. Defaults to `false` |\n| `defaultActiveApplication` | `string` | Sets the hint for active application selection. This helps WebDriverAgent to select the current application if there are multiple items in the active applications list and the desired one is also one of them. The setting is particularly useful for split-screen apps automation. Defaults to `auto`, which makes WebDriverAgent to select the application whose element is located at `screenPoint` location or a single item from the active apps list if the length of this list is equal to one. |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}},{"pageContent":"| `activeAppDetectionPoint` | `string` | Defines the coordinates of the current screen point. WebDriverAgent uses this point to detect the active application if multiple application are active on the screen. The format of this value is `x,y`, where x and y are float or integer numbers representing valid screen coordinates. Setting this value to a point outside the actual screen coordinates might corrupt WebDriverAgent functionality. By default the screen point coordinates equal to 20% of the minimum screen dimension each, e.g. `MIN(w, h) * 0.2, MIN(w, h) * 0.2` |\n| `includeNonModalElements` | `boolean` | Whether returns all of elements including no modal dialogs on iOS 13+. It fixes [cannot find elements on nested modal presentations](https://github.com/appium/appium/issues/13227), but it might make visibility attributes unreliable. You could also enable `shouldUseTestManagerForVisibilityDetection` setting (defaults to `false`) or `simpleIsVisibleCheck` capability to improve the visibility detection. This issue may happen between iOS 13.0 to 13.2 (Xcode 11.0 to 11.2). The query issued in `includeNonModalElements` returns `nil` with newer iOS/Xcode versions and Appium/WDA return proper elements three without this setting being used. Defaults to `false`. |\n| `acceptAlertButtonSelector` | `string` | Allows to customize accept alert button selector. It helps you to handle an arbitrary element as accept button in `accept alert` command. The selector should be a valid [class chain](https://github.com/facebookarchive/WebDriverAgent/wiki/Class-Chain-Queries-Construction-Rules) expression, where the search root is the alert element itself. The default button location algorithm is used if the provided selector is wrong or does not match any element. Example: ```**/XCUIElementTypeButton[`label CONTAINS[c] 'accept'`]``` |\n| `dismissAlertButtonSelector` | `string` | Allows to customize dismiss alert button selector. It helps you to handle an arbitrary element as dismiss button in `dismiss alert` command. The selector should be a valid [class chain](https://github.com/facebookarchive/WebDriverAgent/wiki/Class-Chain-Queries-Construction-Rules) expression, where the search root is the alert element itself. The default button location algorithm is used if the provided selector is wrong or does not match any element. Example: ```**/XCUIElementTypeButton[`label CONTAINS[c] 'dismiss'`]``` |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}},{"pageContent":"| `screenshotOrientation` | `string` | Adjust screenshot orientation for iOS. Appium tries to return a screenshot and adjust its orientation properly using internal heuristics, but sometimes it does not work, especially in landscape mode. The actual screenshot orientation depends on various factors such as OS versions, model versions and whether this is a real or simulator device. This option allows you to enforce the given image orientation. Acceptable values: `auto` (default), `portrait`, `portraitUpsideDown`, `landscapeRight`, `landscapeLeft`. |\n| `boundElementsByIndex` | `boolean` | Whether to look up elements with [`allElementsBoundByAccessibilityElement`](https://developer.apple.com/documentation/xctest/xcuielementquery/1500816-allelementsboundbyaccessibilitye) (default) or [`allElementsBoundByIndex`](https://developer.apple.com/documentation/xctest/xcuielementquery/1500945-allelementsboundbyindex). [This Stack Overflow topic](https://stackoverflow.com/questions/49307513/meaning-of-allelementsboundbyaccessibilityelement) explains the differences. Defaults to `false`. |\n| `keyboardAutocorrection` | `boolean` | Changes the 'Auto-Correction' preference in _Keyboards_ setting. Defaults to `false`. |\n| `keyboardPrediction` | `boolean` | Changes the 'Predictive' preference in _Keyboards_ setting. Defaults to `false`. |\n| `nativeWebTap` | `boolean` | See the description of the corresponding capability. |\n| `nativeWebTapStrict` | `boolean` | See the description of the corresponding capability. |\n| `nativeWebTapTabBarVisibility` | `enum` | Bypass finding whether the existence of the _**tab bar**_ before tapping on the element. It could make native web tap faster. If it's `visible`, tab bar offset will be added without checking the existence of the tab bar. It's `invisible`, the tab bar offset will be `zero`. If you want to leave Appium to check and measure the tab bar offset, unset or set `detect`. Only applicable if `nativeWebTap` and `nativeWebTapStrict` are enabled. Unset by default. |\n| `nativeWebTapSmartAppBannerVisibility` | `enum` | The same as `nativeWebTapTabBarVisibility`, this keyword will bypass finding whether the existence of the _**smart app banner**_. |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}},{"pageContent":"| `nativeWebTapSmartAppBannerVisibility` | `enum` | The same as `nativeWebTapTabBarVisibility`, this keyword will bypass finding whether the existence of the _**smart app banner**_. |\n| `safariTabBarPosition` | `string` | Handle offset of Safari tab bar in `nativeWebTap` enabled interactions. If `platformVersion` was greater than or equal to 15 and iPhone device, the value is `bottom` by default. Otherwise `top`. When the value is `top`, Appium considers offset as the bar length. iOS 15+ environment can customize the bar position in the settings app, so please adjust the offset with this. Acceptable values: `bottom`, `top` |\n| `useJSONSource` | `boolean` | See the description of the corresponding capability. |\n| `pageSourceExcludedAttributes` | `string` | One or more comma-separated attribute names to be excluded from the output. It might be sometimes helpful to exclude, for example, the `visible` attribute, to significantly speed-up page source retrieval. Attributes which can be excluded with `useJSONSource` are frame, enabled, visible, accessible and focused. Defaults to an empty string. Example: `\"visible,accessible\"` |\n| `maxTypingFrequency` | `int` | Maximum frequency of keystrokes for typing and clear. If your tests are failing because of typing errors, you may want to adjust this. Defaults to `60` keystrokes per minute. |\n| `respectSystemAlerts` | `boolean` | Currently we detect the app under test as active if XCTest returns XCUIApplicationStateRunningForeground state for it. In case the app under test is covered by a system alert from the Springboard app this approach might be confusing as we cannot interact with it unless an alert is properly handled. If this setting is set to true (by default it is false) then it forces WDA to verify the presence of alerts shown by Springboard and return the latter while performing the automated app detection. It affects the performance of active app detection, but might be more convenient for writing test scripts (e.g. eliminates the need of proactive switching between system and custom apps). Also, this behavior emulates the legacy active application detection logic before version 6 of the driver. |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}},{"pageContent":"| `webScreenshotMode` | `native` or `page` or `viewport` | Defines the screenshoting logic if the current context is set to a web one. The default value is `native`, which makes the driver to take screenshots from WDA, e.g. the whole device screen including status bars. The `page` mode tries to retrieve the screenshot of the whole active web page, while the `viewport` one only retrieves a shot of the visible viewport. |\n| `useClearTextShortcut` | `boolean` | Whether to use the fastest operation (using IOHIDEvent) to clear texts. In headless mode, simulator's keyboard won't show up anymore after clearing texts using this approach in some cases (see [this issue](https://github.com/appium/appium/issues/20727) for more details). Defaults to true |\n| `limitXPathContextScope` | `boolean` | Due to historical reasons XCUITest driver limits scopes of element context-based searches to the parent element. This means a request like `findElement(By.xpath, \"//XCUIElementTypeButton\").findElement(By.xpath, \"./..\")` would always fail, because the driver only collects descendants of the `XCUIElementTypeButton` element for the destination XML source. The `limitXPathContextScope` setting being set to `false` changes that default behavior, so the collected page source includes the whole page source XML where `XCUIElementTypeButton` node is set as the search context. With that setting disabled the search query above should not fail anymore. Although, you must be careful while building XPath requests for context-based searches with the `limitXPathContextScope` setting being set to `false`. A request like `findElement(By.xpath, \"//XCUIElementTypeAlert\").findElement(By.xpath, \"//XCUIElementTypeButton\")` would ignore the current context and search for `XCUIElementTypeButton` through the whole page source. Use `.` notation to correct that behavior and only find `XCUIElementTypeButton` nodes which are descendants of the `XCUIElementTypeAlert` node: `findElement(By.xpath, \"//XCUIElementTypeAlert\").findElement(By.xpath, \".//XCUIElementTypeButton\")`. |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}},{"pageContent":"| `skipDocumentsContainerCheck` | `boolean` | Whether to apply special handling for the `documents` container type in file management such as pushing/pulling to/from real devices (`false`, the default value), or to treat them in the same way as other container types (`true`). For certain applications having this setting enabled helps to workaround documents upload issues if the `UIFileSharingEnabled` flag is not active in the application manifest.|\n| `autoClickAlertSelector` | `string` | Allows providing a custom [class chain](./locator-strategies.md) selector, which is used to automatically locate an element inside an alert hierarchy, and click it as soon as a new alert is detected. If the provided locator string is invalid then an error is thrown. Providing an empty string disables the feature. This setting has priority over `autoAcceptAlerts` or `autoDismissAlerts` capabilities, e.g. if both are enabled then the destination element to tap on would be selected only based on the provided selector value. If an alert is active, but no element matches the provided selector, then no click would be performed. If two or more elements match the provided selector then the very first matched element is clicked. The selector lookup is performed starting from the root element of the matched alert hierarchy (usually XCUIElementTypeAlert). |\n| `includeHittableInPageSource` | `boolean` | Determines whether the [`hittable`](https://developer.apple.com/documentation/xctest/xcuielement/ishittable) attribute should be included in the page source XML tree. This value reflects whether an element is currently interactive from XCTest’s perspective. Disabled by default due to potential performance impact on large UI hierarchies. Defaults to `false`. |\n| `includeMinMaxValueInPageSource` | `boolean` | Determines whether the `minValue` and `maxValue` attributes should be included in the page source. These attributes represent numeric boundaries for controls like sliders and progress indicators. Disabled by default due to potential performance impact when multiple such elements are present. Defaults to `false`. |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}},{"pageContent":"| `enforceCustomSnapshots` | `boolean` | Being set to `true` enforces WDA to always use a customized snapshotting mechanism using private XCTest APIs instead of the [standard](https://developer.apple.com/documentation/xcuiautomation/xcuielementsnapshotproviding/snapshot()?language=objc) one. By default, WDA only uses the former mechanism for some particular cases where we know that standard snapshots may provide unreliable or distorted results for particular applications, for example, erroneously shifted coordinate values like in the issue [#1085](https://github.com/appium/WebDriverAgent/issues/1085). The main benefit of standard snapshots is they are fast and memory-efficient, although, if it is important for you that the page source attributes fetched by [mobile: source](./execute-methods.md#mobile-source) with `format: 'description'` always 100% match to the XML page source generated by WDA as well as element attributes do, and the test performance is not a defining factor, then change this setting to `true`. Defaults to `false`. |\n| `includeCustomActionsInPageSource` | `boolean` | Determines whether the `customActions` attribute should be included in the page source. This attribute represents one or more custom action names assigned to an element. Disabled by default due to potential performance impact when multiple such elements are present. Defaults to `false`. |","metadata":{"headerPath":"","sectionCount":1,"recursiveSplit":true,"filename":"settings.md","relativePath":"appium-xcuitest-driver/docs/reference/settings.md"}}]