[{"data":1,"prerenderedAt":20},["ShallowReactive",2],{"case-why-we-built-devpeek-h5-debug-en":3,"blog-list-en":11},{"slug":4,"title":5,"summary":6,"date":7,"featured":8,"seoDescription":9,"html":10},"why-we-built-devpeek-h5-debug","Why We Built DevPeek (2): That H5 Page in the App—Debug It on Your PC","Param transform fixed login, but the activity H5 only broke inside the App WebView. Remote debug and capture lived in different windows—so we folded mirroring and our own debug panels into DevPeek.","2026-07-10",true,"DevPeek origin series, part 2: in-app H5 bugs that only show on real devices, the split between remote debug and capture, and how the Debug tab mirrors pages with built-in DOM, Console, and Network panels.","\u003Ch2>Login worked. The activity page did not.\u003C\u002Fh2>\n\u003Cp>In \u003Ca href=\"\u002Fen\u002Fblog\u002Fwhy-we-built-devpeek\u002F\">part one\u003C\u002Fa>, \u003Cstrong>param transform\u003C\u002Fstrong> turned encrypted bodies into “edit the field, hit send.” QA confirmed staging login. Then product dropped another line:\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>“The activity button does not tap on Android—iOS is fine. Can you take a look?”\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>Not a dead API. \u003Ccode>GET \u002Fapi\u002Factivity\u002Fconfig\u003C\u002Fcode> was \u003Cstrong>200\u003C\u002Fstrong> in capture; Mock looked fine too. The issue was the \u003Cstrong>H5 page embedded in the App\u003C\u002Fstrong>: same URL looked OK in Chrome’s responsive mode, but on a real WebView the button sat under the bottom safe area—untappable.\u003C\u002Fp>\n\u003Cp>We know this pattern: it only shows up in an \u003Cstrong>in-app WebView\u003C\u002Fstrong> or on a specific device. Desktop browsers never quite match.\u003C\u002Fp>\n\u003Ch2>Squinting at the phone, windows never line up\u003C\u002Fh2>\n\u003Cp>My first reflex was the usual toolkit.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Remote debug\u003C\u002Fstrong>: enable WebView debugging on Android, plug in USB, hunt the page in \u003Ccode>chrome:\u002F\u002Finspect\u003C\u002Fcode>. Sometimes it never appears—you need a debug build or confirmation it is not an X5 kernel. iOS is its own maze: Safari dev menu, certs, Web Inspector—and the connection drops when the page reloads.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>vConsole \u002F eruda\u003C\u002Fstrong>: logs on the page, but you inject via code or proxy; the DOM tree on a small screen is painful for pixel-peeping.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Capture tools\u003C\u002Fstrong>: Charles shows the H5 XHRs; request\u002Fresponse decrypt fine—but \u003Cstrong>Network is one window, DOM and Console another\u003C\u002Fstrong>. You spot a 500 on \u003Ccode>POST \u002Fapi\u002Fxxx\u003C\u002Fcode> in the list, then switch back to the phone to see which UI triggered it; you align \u003Ccode>TypeError\u003C\u002Fcode> timestamps in Console with rows in capture by hand.\u003C\u002Fp>\n\u003Cp>QA sent a screen recording: “This red button—no response.”\u003C\u002Fp>\n\u003Cp>I stared at six inches of H5, capture on a second monitor, remote debug fighting on a third—none of them could tell me at once \u003Cstrong>“this node on the page”\u003C\u002Fstrong> and \u003Cstrong>“the request it just fired”\u003C\u002Fstrong> were the same story.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fproxy_requestlist.png\" alt=\"DevPeek capture list showing H5 XHR traffic\">\u003C\u002Fp>\n\u003Cp>\u003Cem>Capture shows the H5 requests—but DOM and Console still live on another screen.\u003C\u002Fem>\u003C\u002Fp>\n\u003Ch2>The blocker was never “can’t see traffic”\u003C\u002Fh2>\n\u003Cp>Proxy and SSL were sorted in part one. What grinds H5 joint debug is: \u003Cstrong>traffic is visible; page context lives somewhere else.\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Responsive mode only resizes the viewport—it still runs desktop Chrome, not the in-app WebView. Remote debug is accurate when it connects, but without USB, a debug build, X5 quirks, or when iOS Web Inspector drops on reload, you are back to squinting at the phone.\u003C\u002Fp>\n\u003Cp>DevPeek takes a different path: inject a debug script through the proxy and inspect DOM and Console in the \u003Cstrong>real page’s JS context\u003C\u002Fstrong>; Network shares the capture list, and \u003Ca href=\"\u002Fen\u002Fdocs\u002Fmock\u002F\">Mock\u003C\u002Fa> sits on the \u003Cstrong>same proxy chain\u003C\u002Fstrong>—change a response or error code, tap a button in the page, and the request hits your mocked result without switching tools.\u003C\u002Fp>\n\u003Cp>We are not claiming “more faithful simulation than DevTools.” Injection is limited by CSP, injectable HTML, and the JS runtime; the mirror is rrweb replay, not a GPU video feed; soft keyboard, native chrome, and JSBridge are out of scope. \u003Cstrong>What we optimize for is convenience\u003C\u002Fstrong>—big-screen inspection with page and network (including Mock) in one place—and \u003Cstrong>keeping going when remote debug will not connect\u003C\u002Fstrong>.\u003C\u002Fp>\n\u003Ch2>Mirror in the Debug tab, inspect with our panels\u003C\u002Fh2>\n\u003Cp>Param transform owns \u003Cstrong>encrypted bodies\u003C\u002Fstrong>; for H5, DevPeek owns \u003Cstrong>the page itself\u003C\u002Fstrong>—\u003Cstrong>mobile web debugging\u003C\u002Fstrong> in the main window’s \u003Cstrong>Debug\u003C\u002Fstrong> tab.\u003C\u002Fp>\n\u003Cp>Prerequisites match capture: phone on DevPeek’s proxy, root CA trusted, target hosts in \u003Ca href=\"\u002Fen\u002Fdocs\u002Fproxy-ssl\u002F\">SSL decrypt scope\u003C\u002Fa>. See the checklist in \u003Ca href=\"\u002Fen\u002Fdocs\u002Fdebug-replay\u002F\">mobile web debugging\u003C\u002Fa>; miss a step and the preview stays on “Waiting for device connection.”\u003C\u002Fp>\n\u003Cp>Once that holds, the flow is simple:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Open the \u003Cstrong>Debug\u003C\u002Fstrong> tab and pick the test Android device in the top \u003Cstrong>client tab\u003C\u002Fstrong> (shared with Capture—one device, one tab).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Reload or reopen\u003C\u002Fstrong> the H5 page in the App. The proxy injects a debug script into the HTML; the page connects back over WebSocket and the left preview \u003Cstrong>mirrors\u003C\u002Fstrong> DOM and interaction in real time (rrweb record\u002Freplay—not a video stream of the whole page).\u003C\u002Fli>\n\u003Cli>Below are \u003Cstrong>built-in debug panels\u003C\u002Fstrong>—not embedded Chrome DevTools, but sections designed for proxied mirrors.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>\u003Cstrong>Elements (DOM)\u003C\u002Fstrong>: the tree on the right shares the same source as the mirror. Turn on pick mode, click a node in the preview, the tree highlights it; style and DOM edits \u003Cstrong>go to the real device\u003C\u002Fstrong>, and the mirror updates via rrweb—you inspect on desktop, you change the phone.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Console\u003C\u002Fstrong>: \u003Ccode>console.log\u003C\u002Fcode> and errors from the target page stream into the panel, filtered by page session so old tabs do not bleed logs. You can eval expressions in the \u003Cstrong>real page context\u003C\u002Fstrong>—like remote debug’s console, without wrestling \u003Ccode>chrome:\u002F\u002Finspect\u003C\u002Fcode> first.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Network\u003C\u002Fstrong>: requests from the mirrored page, \u003Cstrong>same source\u003C\u002Fstrong> as the \u003Ca href=\"\u002Fen\u002Fdocs\u002Fcapture\u002F\">capture list\u003C\u002Fa>—same proxy hops, same \u003Ca href=\"\u002Fen\u002Fdocs\u002Fparam-transform\u002F\">param transform\u003C\u002Fa> and \u003Ca href=\"\u002Fen\u002Fdocs\u002Fmock\u002F\">Mock\u003C\u002Fa> rules. Encrypted bodies still show decrypted fields in details; after you Mock an activity API response, Network shows what the page actually received; to resend with edits, switch to Capture, select the row, open \u003Cstrong>Debug API\u003C\u002Fstrong>—no copy\u002Fpaste into Postman.\u003C\u002Fp>\n\u003Cp>Those three panels plus the toolbar (back \u002F forward \u002F reload, URL navigation, throttling) close the loop: inspect against the mirror. For limits (CSP, injection, mirror vs device), see \u003Ca href=\"\u002Fen\u002Fdocs\u002Fdebug-replay\u002F\">mobile web debugging\u003C\u002Fa>—use it when injection works; cross-check on the device when something does not line up.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fproxy_resend_popup.png\" alt=\"Debug API: edit plaintext and resend from the capture list\">\u003C\u002Fp>\n\u003Cp>\u003Cem>Switch to Capture, open Debug API on a row—edit fields and resend without leaving the proxy chain.\u003C\u002Fem>\u003C\u002Fp>\n\u003Ch2>Map Route, Mock—same proxy chain\u003C\u002Fh2>\n\u003Cp>H5 joint debug often hits: \u003Cstrong>the page hard-codes \u003Ccode>https:\u002F\u002Fapi.example.com\u003C\u002Fcode> while your service runs on \u003Ccode>127.0.0.1:8080\u003C\u002Fcode>; or staging is not deployed yet and you need to see how the UI handles an error code.\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>When shipping H5 is not an option, \u003Ca href=\"\u002Fen\u002Fdocs\u002Fmap-route\u002F\">Map Route\u003C\u002Fa> points the host to a local stub; \u003Ca href=\"\u002Fen\u002Fdocs\u002Fmock\u002F\">Mock\u003C\u002Fa> rewrites the body or status—all on the proxy path, \u003Cstrong>no URL change in the WebView\u003C\u002Fstrong>. The Mock tamper dialog is \u003Cstrong>not limited by client tab or main window tab\u003C\u002Fstrong>: tap in the mirrored page on the Debug tab and the tamper UI still opens on hit; Network shares the same data source as the capture list. The Debug tab still mirrors the in-app page; tap in the mirror and you are exercising that same chain, not a second Charles or Postman setup just to align DOM with traffic.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fdocs\u002Ffigures\u002Fmock_tamper_res.png\" alt=\"DevPeek Mock tamper dialog: editing the response phase\">\u003C\u002Fp>\n\u003Cp>\u003Cem>Same proxy chain—tap in the mirror, edit the response in the dialog, and the page receives the tampered result.\u003C\u002Fem>\u003C\u002Fp>\n\u003Ch2>That activity button\u003C\u002Fh2>\n\u003Cp>Back to the button: pick mode in Elements showed the outer \u003Ccode>div\u003C\u002Fcode>’s \u003Ccode>padding-bottom\u003C\u002Fcode> computed short on Android WebView—responsive mode on desktop did not reproduce it; remote debug had not connected yet.\u003C\u002Fp>\n\u003Cp>A quick \u003Ccode>getComputedStyle\u003C\u002Fcode> in Console, and Network confirmed \u003Cstrong>\u003Ccode>POST \u002Fapi\u002Factivity\u002Fjoin\u003C\u002Fcode> never fired\u003C\u002Fstrong> on tap—not a bad API, a blocked hit area. After pushing the style fix to the device, QA clicked through on the mirror, then signed off in the App—no hunching over my desk with their phone.\u003C\u002Fp>\n\u003Ch2>Next\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>Why We Built DevPeek (3): Point the API to localhost without changing H5 URLs\u003C\u002Fstrong>—how Map Route and Mock chain with capture and page debug so you can verify error codes before staging deploys.\u003C\u002Fp>\n\u003Chr>\n\u003Cp>If you are still squinting at in-app H5 on a tiny screen, \u003Ca href=\"\u002F\">try DevPeek\u003C\u002Fa> or say hi on \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FGYPengDev\u002Fdevpeek\u002Fdiscussions\">GitHub Discussions\u003C\u002Fa>—setup: \u003Ca href=\"\u002Fen\u002Fdocs\u002Fdebug-replay\u002F\">mobile web debugging\u003C\u002Fa>, proxy and certs: \u003Ca href=\"\u002Fen\u002Fdocs\u002Fproxy-ssl\u002F\">proxy &amp; SSL\u003C\u002Fa>.\u003C\u002Fp>\n",{"items":12},[13,14],{"slug":4,"title":5,"summary":6,"date":7,"featured":8,"seoDescription":9},{"slug":15,"title":16,"summary":17,"date":18,"featured":8,"seoDescription":19},"why-we-built-devpeek","Why We Built DevPeek (1): HTTPS Decrypted, Body Still Gibberish","The night before a release, TLS was already open—but changing one request field still meant digging up encrypt\u002Fdecrypt scripts. That pushed us toward a proxy tool with business-layer crypto built in—and DevPeek started there.","2026-07-09","DevPeek origin series, part 1: the manual request-body encrypt\u002Fdecrypt grind—and why we set out to build a proxy tool that owns business-layer crypto.",1783662155616]