The Road to Delphi

Delphi – Free Pascal – Oxygene

Changing the UA (User Agent) of a TWebBrowser component

29 Comments

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.

Author: Rodrigo

Just another Delphi guy.

29 thoughts on “Changing the UA (User Agent) of a TWebBrowser component

  1. Pingback: Changing the UA (User Agent) of a TWebBrowser component

  2. Nice Rodrigo & thanks.
    Tom

  3. 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!

    • 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;

  4. dude, it works perfectly! but a question. What does WebBrowser1.handleNeeded do? Cause i didnt put it and it still works!

    • 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

  5. Ok got it now. Thank you a lot!

  6. 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?

  7. 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

    • 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.

  8. Thank you for your time.
    I will look it and if I find something I will post back.

  9. Interposer class of the TWebBrowser ? WTF? Where do I put this code?
    Can you make the example downloadable?

  10. Hi Rodrigo, should this work in Delphi7 too?

    • Yes, this code should work in Delphi 7 without problems.

      • 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

  11. 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?

    • 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?

      • 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.

  12. Isn’t it better to change via SetInternetOption / UrlMkSetSessionOption ??

    • 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.

  13. 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.

  14. Pingback: Anonymous

  15. 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

  16. 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.

    • 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.

  17. Great! Embarcadero never thought to include this patch in the official component?

  18. Rodrigo, thank you a lot. That is working very good, you helped me a lot!!!

Leave a reply to Rodrigo Cancel reply