In a member function (like your Node::insert()), all members of the class, e.g. data,  are accessible simply by their unqualified names.
The name is accessible without prefix because a (non-static) member function can only be called from an object of the class, e.g. Node n; n.insert(1);. n is the object, and the compiler will interpret data as the data belonging to n.
I don't know Python but I assume that the self parameter corresponds to C++'s implicit this parameter which is available in every non-static member function and points to the object the function is called with, here n.  The difference is apparently that this  is implicitly passed; it does not appear explicitly in the parameter list. That is a somewhat arbitrary early C++ design decision; Bjarne Stroustrup could as well have made the parameter explicit. The main benefit is a reduction in redundancy (this is always there for a non-static member function, so why mention it?).
Therefore, if you like you can prefix data with this-> to be explicit. That may have some merit for long functions in classes with many members where the casual reader is unsure whether data is a member of local variable or parameter. Some anal coding guidelines require this-> for those reasons, but typically it's only done to resolve ambiguities like name clashes with global variables. A better way to avoid name clashes and recognize members is to require an m... prefix for them, as in mData or m_data, depending on your naming habits.
The code to insert a new value in the tree and not do anything if it's already there looks very much like your Python blueprint:
    void insert(int val){
        if (data == val) 
            return;
        else if (val < data)
            if (left)
                left.insert(val);
            else
                left = Node(val);
        else
            if (right)
                right.insert(val);
            else
                right = Node(val);
    }
This is untested and probably contains typos and perhaps an if/else logic error. In real code I would always curly-brace all code that depends on an if/else, even if it's just one line. That makes maintenance easier: Removing or adding branches here may inadvertently change the association of else blocks or introduce a syntax error.
By the way, the comparison of an integer with a pointer in your original suggestion is weird and does not serve a purpose; generally such comparisons are unusual, and the pointer should be cast to a suitable integer type for that (probably std::intptr_t).