The user agent strings identify what a user is using to access a web resource. some websites may deliver (slightly) different content depending upon what browser is being used. For example, if you use a iPhone user agent to browse to a WordPress site like https://theroadtodelphi.wordpress.com the result will see something like this :
As you can see the content is designed to fit with a mobile device. in this post I will show how you can change the user agent of a TWebBrowser component.
to change the UA of TWebBrowser you must call the OnAmbientPropertyChange event of the IOleControl interface with the DISPID_AMBIENT_USERAGENT flag and in the implementation of the Invoke function for the IDispatch interface set the value for the New User Agent String.
check the next source code using a interposer class of the TWebBrowser which declare a new property called UserAgent in the component.
const DISPID_AMBIENT_USERAGENT = -5513; type TWebBrowser = class (SHDocVw.TWebbrowser, IDispatch) private FUserAgent: string; procedure SetUserAgent (const Value: string); function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT; stdcall; public property UserAgent: string read FUserAgent write SetUserAgent; constructor Create(AOwner: TComponent); override; end;
and the implementation
constructor TWebBrowser.Create(AOwner: TComponent); begin inherited Create(AOwner); FUserAgent:=''; end; function TWebBrowser.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT; begin //check if the DISPID_AMBIENT_USERAGENT flag is being processed and if the User Agent to set is not empty if (FUserAgent <> '') and (Flags and DISPATCH_PROPERTYGET <> 0) and Assigned(VarResult) and (DispId=DISPID_AMBIENT_USERAGENT) then begin //set the user agent POleVariant(VarResult)^:= FUserAgent+#13#10; Result := S_OK; //return S_OK end else Result := inherited Invoke(DispID, IID, LocaleID, Flags, Params, VarResult, ExcepInfo, ArgErr); //call the default Invoke method end; procedure TWebBrowser.SetUserAgent(const Value: string); var Control: IOleControl; begin FUserAgent := Value; //the current interface supports IOleControl? if DefaultInterface.QueryInterface(IOleControl, Control) = 0 then Control.OnAmbientPropertyChange(DISPID_AMBIENT_USERAGENT); //call the OnAmbientPropertyChange event end;
Now to use the above code your only need to add a TWebBrowser component to your form, then add the declaration of the New TWebBrowser class to begin of your unit and finally you must add the implementation of the methods show in this article.
Now to set the new user agent, you only must set the UserAgent property.
WebBrowser1.UserAgent:='Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3'; WebBrowser1.Navigate(EditURL.Text);
check the screen-shots for the demo application
For more info about User Agent strings check these links
Understanding User-Agent Strings
RFC 1945 – 10.15 User-Agent
Check the source code on Github.
Pingback: Changing the UA (User Agent) of a TWebBrowser component
March 12, 2011 at 8:55 am
Nice Rodrigo & thanks.
Tom
August 7, 2011 at 9:45 am
hey. Great app works perfectly. But I have a problem. I want the twebbrowser’s user agent to change once it’s created. I implemented your code in an app I’m making, but the user agent changes after the 2nd navigation and refresh! help please?
BTW great site and great articles!
August 7, 2011 at 4:23 pm
It seems which the DISPID_AMBIENT_USERAGENT. It called after of the first navigation, so to handle this you have two options
1) calling the Navigate method with about:blank and then call again the page where which to go.
procedure TFrmMain.FormCreate(Sender: TObject);
begin
WebBrowser1.HandleNeeded;
WebBrowser1.UserAgent:=CbUserAgent.Text;
WebBrowser1.Navigate('about:blank');
WebBrowser1.Navigate('https://theroadtodelphi.wordpress.com');
end;
2) passing the useragent string directly to the navigate method the first time which you load the page
procedure TFrmMain.FormCreate(Sender: TObject);
Var
PostData : OleVariant;
begin
WebBrowser1.HandleNeeded;
WebBrowser1.UserAgent:=CbUserAgent.Text;
PostData:=EmptyParam;
WebBrowser1.DefaultInterface.Navigate('https://theroadtodelphi.wordpress.com', EmptyParam, EmptyParam, PostData, 'User-Agent:'+CbUserAgent.Text+#13#10);
end;
August 8, 2011 at 6:48 am
dude, it works perfectly! but a question. What does WebBrowser1.handleNeeded do? Cause i didnt put it and it still works!
August 8, 2011 at 1:10 pm
The HandleNeeded is to force to the TWebBrowser to draw the webpage creating a screen object for the control even if the component is not visible (ex. in a tab control). So in this case is optional
August 9, 2011 at 1:59 pm
Ok got it now. Thank you a lot!
February 7, 2012 at 11:55 am
This is a great article but I have a problem with the code.
Using Delphi 2009 when I recompile the project (with no changes) it doesn’t work.
Any guess why this happens?
February 7, 2012 at 12:00 pm
Do you receive any error message?
February 7, 2012 at 12:07 pm
No nothing, not even warnings upon compilation.
Application starts but I get “Navigation to the webpage was canceled”.
I uploaded an image here: http://i.imgur.com/G7ggW.png
February 7, 2012 at 12:35 pm
I just test the sample application in Delphi XE (I don’t have delphi 2009) and works fine, so sorry but for the moment I don’t know what can cause this issue.
February 7, 2012 at 12:38 pm
Thank you for your time.
I will look it and if I find something I will post back.
November 15, 2012 at 4:32 pm
Interposer class of the TWebBrowser ? WTF? Where do I put this code?
Can you make the example downloadable?
November 15, 2012 at 5:23 pm
The article includes a sample project, try this http://dl.dropbox.com/u/12733424/Delphi/User%20Agent%20Switcher.rar
January 14, 2013 at 9:11 pm
Hi Rodrigo, should this work in Delphi7 too?
January 15, 2013 at 9:36 am
Yes, this code should work in Delphi 7 without problems.
January 15, 2013 at 7:26 pm
Well…
I don’t know if it’s doing what it should
I’m trying to tackle a situation for which
i thought your example here was a solution
maybe it’s not really the case?
I am developing an HTML table producer for an HTML editor
and i need to monitor in the table producer the produced HTML/css code
since I’m not sure that this is related to your UA switcher
i have dropped my specific situation here
http://www.polpero.ca/prj/Delphi/TWebBrowser/
maybe you can judge by yourself ?
thanks
February 6, 2013 at 9:30 am
Hi Rodrigo,
I’m trying to create a desktop client and I’d like to add a proxy configuration option. So it could work with a diferent proxy than the system one.
I can’t find the solution. Tried to investigate your way to set UA but I don’t find here the answer.
Please, could you help me?
February 6, 2013 at 10:07 pm
Hi Javier, I don’t see the relation between set the User Agent and a proxy. So I’m guessing, are you trying to setup a new or existing proxy to use in a TWebBrowser control?
February 8, 2013 at 5:08 pm
I thought that maybe it could be set host, port and type of a proxy server to a TWebBrowser using the same method described in this post for setting up the user agent.
It is not possible but, could you help me by mail or with an other post in your blog that explains how to add this capability to a Delphi application? Setting up a proxy server in a Delphi application/component.
August 8, 2013 at 6:29 am
Isn’t it better to change via SetInternetOption / UrlMkSetSessionOption ??
August 8, 2013 at 9:09 am
Depends what you need, The UrlMkSetSessionOption and InternetSetOption methods can be used to set the UA but for the current internet session and for all the sessions, this article shows how set the user agent in each instance of the webbrowser.
April 24, 2014 at 1:30 pm
Hi,
I’ve tested this code on Windows 8.1 and Internet Explorer 11.
If I go to http://www.whatsmyuseragent.com/ the fake User Agent is showned.
but If I call
javascript:alert(navigator.userAgent)
the real user agent is displayed.
I didn’t know before, why some flash players reported the real UA even if I used a fake one.
Do you know if this is happening only with IE 11 ? or we can fix it somehow.
Thanks.
Pingback: Anonymous
October 15, 2014 at 4:16 am
With this web not works change agent,
http://ivanrublev.me/kml/
some solution to see this web in Twebbrowser?
curiously in my IE 11 of Windows8.1 x64 this web works
February 11, 2015 at 11:49 am
In your demo, when I select the last user agent in the list (Mozilla 5, U, msi90, winnt, en) I get this error msg in the browser:
Not Acceptable!
An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.
February 11, 2015 at 12:08 pm
Maybe the user agent string is not recognized by the site, You can try with another user agent string. remember the UA listed in the demo App are just samples, you can use any valid UA.
March 12, 2015 at 8:48 am
Great! Embarcadero never thought to include this patch in the official component?
April 24, 2015 at 3:44 pm
Rodrigo, thank you a lot. That is working very good, you helped me a lot!!!