Why I am not a fan of Google Analytics

“Integrating your search and social efforts brings better brand visibility and higher conversion rates.”

— Jim Yu, BrightEdge

Google Analytics is a tool developed by Google, which allows web site owners to embed it on their pages and collect various information about their users, view a bunch of charts based on the collected data and see the various reports. That is, Google Analytics aims to provide exemplary statistics about the visitors of your site. Beyond doubt, it’s a fantastic tool to help to rule your business. Anyway, I bet you’ve already heard of it. That was a description for developers.

“If you want to keep a secret, you must also hide it from yourself.”

— George Orwell, 1984

Now, let me reintroduce Google Analytics (GA), and I’ll be honest this time. So, Google Analytics allows web site developers to track your actions on the web pages you use. That is, GA allows big bosses to spy on you. Never heard of it? By the way, do you know you use GA every day? Have you been a happy customer? That was a description for everyone else.

The problem

Let’s imagine that you were teleported to a mysterious dark room with a table-lamp and a computer (since GA is the culprit, you could imagine you’re in a basement of Google Labs somewhere in the spacious desert of Texas). You figured it’s boring there and decided to use the computer and read some news. You opened a web browser and visited your favourite web site. Before loading the web site’s content, the browser asks you a simple question: “Do you want to enable tracking of your activity while staying on this site? (Yes/No)”. What is your answer? Think about it duly. Do you think the grimy grim man in black behind you would be happy to see you choosing “No” (you haven’t spotted him initially, because he was under the veil of mystery and basement darkness)? Righto, let’s suppose, your answer was “Yes” (or most likely “I don’t care”, which means the same). The web site content was very interesting and you’ve spent 2 hours reading it. So after you’ve finished reading, you closed the tab. But before closing, the browser demands you to answer one last time: “Do you want to send the activity we just recorded to our servers? (Yes/No)”. This activity is data generated by you while browsing the content: your actions and behaviour while working with input devices of the computer. Hence, it’s your data they want to send, which belongs only to you. Do you usually share your stuff with strangers? Me neither. I think it’s clear now that no-one wants to share their data without permission.

Let’s teleport back to where you were. Oh, hello! You’re in a comfortable roomy room now. There’s a computer in the room, of course (your computer this time). Why not spend another couple of hours reading comics and other funny stuff? No sooner said than done. You visit a web site with comics and suddenly your browser asks the same questions you saw while in the basement. There’s no suspicious men around this time. You safely answer “No” on every question it asks. So, you finished using the computer, but the day is not over yet and there’s still time left on your hands. With that being said, you decide let’s go for a… but wait for a second, did you notice something strange? When you’re free to choose, you usually want to stay private.

First they came for the Socialists, and I did not speak out — Because I was not a Socialist.

Then they came for the Trade Unionists, and I did not speak out — Because I was not a Trade Unionist.

Then they came for the Jews, and I did not speak out — Because I was not a Jew.

Then they came for me — and there was no one left to speak for me.

— Martin Niemöller

Of course, as I previously mentioned, you may not care. Privacy may not be your concern if it doesn’t touch upon you directly. However, how do you like this: every user on the internet, if he knows your email, phone, username or full name, can find your Facebook account without asking you for a link. Just navigate to the special page and enter a random number from your phone book. You’d be surprised, but you can easily find an unknown person who rang you last month from a number that is not stored on phone and called you a moron. Now, imagine that Google knows everything about you. It knows everything about me, too. I use GMail, Android and Chrome a lot. Google Analytics seems to be a “logical” addition to that soup, so they could spy on every level of your internet activity.


The “magic” search

How to protect yourself from Google Analytics

Whether you use GMail, Android, Chrome or not it is your personal choice. You can easily opt-out from using those products. On the contrary, Google Analytics is everywhere and it’s free. It means that GA can be added to every web site, including the web site of your dog. Because GA executes on the client side, the best protection would be to disable JavaScript (JS) in your browser. As an additional bonus, you will also block any other possible tracking activity (GA is not the only malicious script, but the most ubiquitous). I don’t recommend to go this way, though. Although you will be well protected and your pages will start loading almost instantly, most likely you will encounter some issues. The problem is that the modern web is covered in a plaid of JS. You will not be able to browse some web sites and some features previously known to work before can become unresponsive. JS is the most popular programming language and it is becoming more and more popular, so your browsing experience will be even worse in a couple of years.

There’s another option: Google Analytics Opt-out Browser Add-on. Go visit the page. You’ll discover that you are on Google.com. I haven’t used their add-on, but I believe it’s bullshit. How can you trust an add-on from the same company that spies on you? Yet another option is to use yet another extension by a different company. Check out Ghostery. I prefer this option, because it can block many other tracking scripts. However, while writing this article, I discovered it’s not open source. It means that only goodness knows what their extension does with my data. I’m not aware of a similar open source tool, though. Still, I find this extension the lesser of two evils. If you are hardcore, you can develop your own way to cut out unwanted scripts. The community will hug you tightly and thank you warmly.

You still may not want to use any protection, and you know what? I can understand your choice. But it’s important to keep in mind that sometimes they spy on you without your will, even when you don’t expect it. My advice to everyone: choose wisely what you share with unknown people and random web sites.

Wrapping up


Every thing in our world has shortcomings and Google Analytics is no exception. However, in case of GA the shortcoming is fatal: it is its main feature. You don’t even have to register a Google account to be tracked by them. As of 2012, 55% of the top 10,000 web sites on the internet use GA. I, as a programmer, am truly impressed by GA. It’s a really magnificent and successful product. I, as a user, strongly dislike it. It’s the plague. I respect big web sites like Wikipedia that do not use GA. I encourage you to respect the users of your web site as well and forget about GA or similar tools forever. Honor your users, because they are what make you successful.

Did you know?

Did you know that Google Analytics is not the only product that violates your privacy? There’s a Russian clone of GA called Yandex.Metrica. It is a very popular service in Runet¹. Some web sites even use both GA and Metrica on the same web site.


¹ — Russian-speaking part of the internet (Russia, Belarus, Ukraine, Kazakhstan)

So what is “binding.pry” exactly?


The Japanese translation (by yui-knk)

The very first feature that you learn about Pry is undoubtedly “binding.pry”. You put it here, there and everywhere; you’re happier than you’ve ever been before. In simple words: “binding.pry” makes your life a lot easier. But, have you ever wondered what “binding.pry” is? It appears so simple that you don’t even think of the details. When I first started to use Pry, I simply cargo-culted it. “binding.pry” seemed to me like some mysterious sorcery. Obviously, that’s not true, but when you learn something new things always appear more mysterious than they really are. By the end of this article you should have a solid understanding of one of the oldest and most interesting features of Pry.

The story of a little expression with incredible power


We can use “binding.pry” almost anywhere. For instance, when you launch Pry via the command-line interface its default context is always “main”¹. Pry displays this information in the prompt (“[1] pry(main)>”). The prompt is dynamic: it always displays the current context.

The following snippets demonstrate a number possible places you can insert a “binding.pry”. The only difference is the context.

“binding.pry” divided into “binding” and “pry”

It’s time to slightly lift the veil. I’m sure a few of you know about the Binding class from Ruby; but I’m also sure an even larger number have never heard of it. It’s not really a feature that every Ruby programmer needs to be familiar with — but this is exactly what powers “binding.pry”. Let’s analyse this further below.


“binding” is a method. It always returns a new instance of the Binding class.

binding.class #=> Binding
binding #=> #<Binding:0xa9dcefc>
binding #=> #<Binding:0xa9ee490>

You can invoke it anywhere you want, because it is a method of the Kernel module and Kernel methods are available on every object. One more important thing to know is that the Binding class can’t be instantiated directly². The “binding” method is the only interface.

So what exactly is a “binding”? A binding is a like a “snapshot” of everything available at the moment of instantiation: current value of “self”, local variables, methods, instance variables and more. Think of it as a room in the house full of items. There can be many rooms. Each room has its own set of items and a window. In Pry internals such a place is called a context. But foremost, in order to get an item from a room, we need to pry open a window and creep into a house, so we can see what’s available around.

Thanks to the Binding class, the so-called window can be implemented with a single method call. Let’s call it “Room#window” and put a teddy bear in it. Our aim is to take out that bear.

You can also ask Maria to take back the teddy bear. Thanks to “binding” we are able to evaluate Room’s code in the context of Maria, so no-one will cry later.



Onwards to the other part of “binding.pry” expression, “pry”. It turns out that you can invoke “pry” almost on every Ruby object. That's possible because it is defined on Object, the ancestor of every Ruby class. The method being invoked on a random object, starts a new Pry session in the context of that object.

[1] pry(main)> ['andrew', 'alexander', 'vladimir'].pry
[1] pry(#<Array>)> map &:capitalize
=> ["Andrew", "Alexander", "Vladimir"]
[2] pry(#<Array>)> exit
=> nil
[2] pry(main)> "do you hear me?".pry
[1] pry("do you hear me?")> upcase
[2] pry("do you hear me?")> exit
=> nil
[3] pry(main)>

Remembering the examples in the beginning of this article and looking at the snippet above might put an idea into your head: we can get rid of constant typing of “binding” and just write “pry” instead, can't we? It turns out, we can. However, “binding.pry” and “pry” are not interchangeable. They start Pry sessions in different contexts.

The following example uses “binding.pry”. A Pry session is started in the context of a Song instance and the “music” local variable is accessible.

[1] pry(#<Song>)> music
=> "rock & roll"

Let’s slighlty modify the “Song#play” method and use “pry” this time. Again, the session starts in the context of the Song instance, but things work a bit different, now. In this case the “music” local variable is not accessible. Although we invoke “pry” in the scope of “Song#play” method, the Pry read-eval-print-loop starts not where you might expect. The local variable is unreachable, because Pry does not operate on the binding of the “Song#play” method. Instead, it operates directly on the instance, implicitly accessible via “self”.

[1] pry(#<Song>)> music
NameError: undefined local variable or method `music' for #<Song:0xbd2fe00>
from (pry):7:in `__pry__'
[2] pry(#<Song>)> whereami
Inside #<Song>.
[3] pry(#<Song>)> object_id == $old_id
=> true

The “self” keyword has also acquired its “pry” method from Object (not literally, since it’s just a placeholder for other Ruby objects that have that method defined). So “self.pry” and “pry” are totally equal.

There is one minor case when you can’t invoke “#pry”, though. Unfortunately, Pry doesn’t support instances of BasicObject, so you can’t pry into them. The reason is that BasicObject is the superclass of Object, and it sits even higher in the ancestry chain. It means that its instances don’t have the “pry” method. We can’t just move “Object#pry” to “BasicObject#pry”, because BasicObject instances don’t have the “binding” method, on which “Object#pry” relies.

basic = BasicObject.new #=> #<BasicObject:0x512c30c>
basic.pry #=> NoMethodError: undefined method `pry' for #<BasicObject:0xa258618>

Remember, you get “binding” from the Kernel module and Object is the only class, which includes it. This is by Ruby’s design. Some people want to see the binding support for BasicObject, but this is unlikely to happen in the near future. In Pry lobby interviews there were attempts to work around this, but they didn’t go too far.

Although Pry can’t support BasicObject instances, it supports BasicObject class itself, because Class instances do have bindings.

[1] pry(main)> BasicObject.pry
[1] pry(BasicObject)> __id__
=> 81839890

Another interesting feature of the “pry” method is that it supports arguments. So pry, self.pry and pry(self) are the exact same expressions. In fact, it accepts any Ruby objects, not only “self”. Just imagine, it’s only a one method, but how much power it is endowed with!

In the example below you can clearly see that “pry” is not like the “cd” command. It doesn’t store a chain of bindings (known as a binding stack). Instead, it always creates a new session, with its own binding stack (look at the “[1]” from the prompt, it doesn’t continue the previous counter, but starts a new one, without modifying the existing counter).

[1] pry(main)> pry 1337
[1] pry(1337)> pry ''
[1] pry("")> pry :awesome!
[1] pry(:awesome!)>
[1] pry(:awesome!)> nesting
Nesting status:
0. :awesome! (Pry top level)
[2] pry(:awesome!)> exit
=> nil
[1] pry("")> nesting
Nesting status:
0. "" (Pry top level)

The “pry” method also accepts the second argument: a hash of options. Most of the time you don’t need it. However, it won’t hurt you to know slightly more than an average Pry user, because you’re the special one. You can check the full list of options in the “pry_instance.rb” file (as of Pry v0.9.12.2). That list is quite big, so let me show you some of the insteresting options: “:output” and “:extra_sticky_locals”.

In the next example I did a couple of things. Firstly, I redirected all the output from a nested Pry session to a local variable called “output_history” and then printed its contents. Secondly, I injected a new sticky local variable. Sticky variables are shared across all Pry sessions and they’re accessible in any context. Just bear in mind that since the “pry” method creates a new Pry session, the hash options don’t affect the parent session: they’re valid only for the new session.

[1] pry(main)> output_history = StringIO.new
=> #<StringIO:0xab8978c>
[2] pry(main)> :universe.pry :output => output_history, :extra_sticky_locals => { :time => Time.now }
[1] pry(:universe)> whereami
[2] pry(:universe)> ls
[3] pry(:universe)> time
[4] pry(:universe)> Help me out!
[5] pry(:universe)> exit
=> nil
[3] pry(main)> puts output_history.string
Inside :universe.
Comparable#methods: <  <=  >  >=  between?
  <=>  =~       capitalize  empty?    inspect  match               size   swapcase  to_sym
  ==   []       casecmp     encoding  intern   next                slice  to_proc   upcase
  ===  __pry__  downcase    id2name   length   pretty_print_cycle  succ   to_s    
locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_  time
=> 2013-05-25 14:22:34 +0300
NoMethodError: undefined method `out!' for :universe:Symbol
from (pry):3:in `__pry__'
=> nil
[4] pry(main)> time
NameError: undefined local variable or method `time' for main:Object
from (pry):8:in `__pry__'

“binding” and “pry” pulled together


So now, since you know a lot more about bindings and prys, it’s time to answer the main question. How does the Pry REPL know where to start a read-eval-print-loop? Why does “binding.pry” work? In simple words, when you invoke “pry” on an object, Pry gets the binding of that object and starts a REPL in its context. The mechanism for retrieving a binding is simple and robust. Its name is “Pry.binding_for”.

b = Pry.binding_for(:universe) #=> #<Binding:0xb2e7ad8>
b.eval('self') #=> :universe

You can pass any Ruby object to it. If you pass a Binding instance or a top-level binding, it returns it. But with other parameters it works a little bit different. It calls __binding__ method on “:universe” and it returns the corresponding binding. The question is where does “:universe” obtain this method? It is defined on Object, too.

Another supplementary method is used for retrieving a binding. Whenever you call “pry” on something, Pry internally creates a new method on that object called __pry__.

[1] pry(main)> :universe.__pry__
NoMethodError: undefined method `__pry__' for :universe:Symbol
from (pry):1:in `__pry__'
[2] pry(main)> :universe.pry
[1] pry(:universe)> :universe.__pry__
=> #<Binding:0xadf1a74>
[2] pry(:universe)> 
=> nil
[3] pry(main)> :universe.__pry__
=> #<Binding:0x91a27c4>
[4] pry(main)> :universe.__pry__.eval('self')
=> :universe

This is not a rocket science, it simply retrieves a binding of an instance (recall “Room#window”. “__pry__” is exactly the same). Albeit this method is not for public use, you can do some interesting things with help of it. Namely, once “__pry__” is defined, you can peek into objects without prying into them. It’s kind of a gateway for accessing an object’s internals.

[1] pry(main)> 1337.pry
[1] pry(1337)> @leet_number = :so_leet
=> :so_leet
[2] pry(1337)> exit
=> nil
[2] pry(main)> 1337.__pry__.eval('@leet_number')
=> :so_leet

Additionally, as I already mentioned, Pry defines the “__binding__” method on every object. It’s already there, so you don’t need to call “pry” on it.

[1] pry(main)> :universe.__binding__.eval 'upcase'

Why are there two exactly the same methods? Because they are not the same. “__pry__” is even more internal than “__binding__”, as the latter utilises the former. So “__binding__” is more powerful. There is no “__pry__” for classes an modules, but there is always “__binding__”. Do you remember that Pry can start its session in the context of a Class? This is exactly what “__binding__” is for.

A = Class.new
A.__pry__ #=> NoMethodError
A.__binding__ #=> #<Binding:0xb0e8570>

exit # Exits from the nested session.
A.__pry__ #=> NoMethodError, still undefined.

So “__pry__” is for instances. For the rest there’s “__binding__”. The context of evaluation in this case is “self“, as always. Modules also behave as Classes.

[1] pry(main)> M = Module.new
=> M
[2] pry(main)> M.__binding__.eval('def magnifico; :splendid end')
=> nil
[3] pry(main)> include M
=> Object
[4] pry(main)> magnifico
=> :splendid

This is it. Imagine a REPL. Imagine a context. Tie them together.

[1] pry(main)> loop do
             |   print '>> '
             |   puts "=> #{ TOPLEVEL_BINDING.eval(gets) }"
             | end
>> def hello; :hi end
>> hello
=> hi

Then, just spice up everything with bindings and you are ready to be famous.

A historical note

Roughly speaking, in the early days of Pry everything worked exactly the same. The API was different, though. There was no “binding.pry” and you had to “Pry.into(object)”. Nowadays the mechanism has become more robust and easier to use. I encourage you to check Pry as it was 3 years ago. It was only 125 lines of code. It’s interesting that the README claimed that “Pry does not pretend to be a replacement for IRB”. And for the full-featured replacement it was recommended to use ripl.


“binding.pry” is a very powerful expression. “binding” is powerful by itself, but if it is assisted with Pry, it reveals unbelievable possibilities. When Pry starts, it always starts in some context. The default context is “main” (just like in IRB). But with help of bindings it can load itself wherever a binding is available. It extends binding’s features with its own ones, allowing excellent introspection experience, and in the end you get the best Ruby debugging tool ever existed.


If you want to become more advanced with Pry and bindings, I offer you three tasks. The first one is very simple and it’s suitable for every reader of this article. The next one is simple, too, but it requires some thinking. The last one is really hard. It’s for passionate Pry users only. It makes you to poke around the Pry source code, so please, value your time.

Task 1

Figure out why the msg local variable is not accessible. How to inspect its value?

Task 2

Run the following snippet in your Pry console.

Without using Pry commands (e.g. “cd”), how to get the value of the count local variable?

Task 3

How to swap the top-level binding with a fresh one?

Note that “count = nil” is not the correct solution, as it doesn’t swap the current binding with a fresh one. Focus on the very bindings, not on garbage collection and other unrelated things that you might thought of. To complete this, you only need to swap the current binding object.

Additional reading

Some people can write better than me. These article are not about Pry, but by reading them you’ll be able to understand “binding.pry” even deeper. I heartily recommend to check them out.

Did you know?

Did you know that IRB has basic support for bindings, too? It's not really enjoyable to work with them there, though.

irb(main):001:0> irb "do you hear me?"
irb#1(do you hear me?):001:0> upcase


Huge thanks to a friend of mine and the creator of Pry, John Mair, for helping me to polish my language.

Big thanks to Duncan Beevers for the criticism. I love to be criticised and Duncan is very sincere.

¹ — More information on “main” can be found in the “What is the Ruby top-level” by John Mair.

² — that is, we can’t create our own Binding instances using the “#new” method, like we can do it with many other Ruby standard classes.

Binding.new #=> NoMethodError: undefined method `new' for Binding:Class

Binding is somewhat similar to Symbol: there is no need in their instantiation. A binding, just like a symbol is already here, ready at hand.